blob: fa9adf9acd2b534d9d563158d802e420ca67e650 [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
Mike Frysinger499ca392020-04-28 07:35:54 -040017import sys
Zdenek Behan508dcce2011-12-05 15:39:32 +010018
Aviv Keshetb7519e12016-10-04 00:50:00 -070019from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050020from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080021from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070022from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070023from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050024from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080025from chromite.lib import toolchain
Mike Frysingere652ba12019-09-08 00:57:43 -040026from chromite.utils import key_value_store
Mike Frysinger35247af2012-11-16 18:58:06 -050027
28# Needs to be after chromite imports.
Mike Frysingerabb7d812020-05-15 00:13:10 -040029import lddtree # pylint: disable=wrong-import-order
Zdenek Behan508dcce2011-12-05 15:39:32 +010030
Mike Frysinger31596002012-12-03 23:54:24 -050031if cros_build_lib.IsInsideChroot():
32 # Only import portage after we've checked that we're inside the chroot.
33 # Outside may not have portage, in which case the above may not happen.
34 # We'll check in main() if the operation needs portage.
Mike Frysinger27e21b72018-07-12 14:20:21 -040035 # pylint: disable=import-error
Mike Frysinger31596002012-12-03 23:54:24 -050036 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010037
38
Mike Frysinger499ca392020-04-28 07:35:54 -040039assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
40
41
Matt Tennantf1e30972012-03-02 16:30:07 -080042EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010043PACKAGE_STABLE = '[stable]'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010044
45CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070046ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010047STABLE_OVERLAY = '/usr/local/portage/stable'
48CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010049
50
Mike Frysinger66bfde52017-09-12 16:42:57 -040051# The exact list of host toolchain packages we care about. These are the
52# packages that bots/devs install only from binpkgs and rely on the SDK bot
53# (chromiumos-sdk) to validate+uprev.
54#
Mike Frysinger66bfde52017-09-12 16:42:57 -040055# We don't use crossdev to manage the host toolchain for us, especially since
56# we diverge significantly now (with llvm/clang/etc...), and we don't need or
57# want crossdev managing /etc/portage config files for the sdk
58HOST_PACKAGES = (
59 'dev-lang/go',
Yunlian Jiang2cb91dc2018-03-08 10:56:27 -080060 'dev-libs/elfutils',
Mike Frysinger66bfde52017-09-12 16:42:57 -040061 'sys-devel/binutils',
Mike Frysinger66bfde52017-09-12 16:42:57 -040062 'sys-devel/gcc',
63 'sys-devel/llvm',
64 'sys-kernel/linux-headers',
65 'sys-libs/glibc',
66 'sys-libs/libcxx',
67 'sys-libs/libcxxabi',
Manoj Guptade64cb22019-03-31 18:48:58 -070068 'sys-libs/llvm-libunwind',
Mike Frysinger66bfde52017-09-12 16:42:57 -040069)
70
Mike Frysinger785b0c32017-09-13 01:35:59 -040071# These packages are also installed into the host SDK. However, they require
72# the cross-compilers to be installed first (because they need them to actually
73# build), so we have to delay their installation.
74HOST_POST_CROSS_PACKAGES = (
Manoj Gupta65f88442018-04-12 22:42:19 -070075 'dev-lang/rust',
Bob Haarmane75b16b2020-09-29 20:48:53 +000076 'dev-lang/rust-bootstrap',
Mike Frysinger61a24392017-10-17 17:14:27 -040077 'virtual/target-sdk-post-cross',
Patrick Georgi043ce6e2019-02-20 22:27:09 +010078 'dev-embedded/coreboot-sdk',
Mike Frysinger785b0c32017-09-13 01:35:59 -040079)
80
81# New packages that we're in the process of adding to the SDK. Since the SDK
82# bot hasn't had a chance to run yet, there are no binary packages available,
83# so we have to list them here and wait. Once it completes, entries here can
84# be removed so they'll end up on bots & dev's systems.
85NEW_PACKAGES = (
Bob Haarmane75b16b2020-09-29 20:48:53 +000086 'dev-lang/rust-bootstrap',
Mike Frysinger785b0c32017-09-13 01:35:59 -040087)
88
Rahul Chaudhry4b803052015-05-13 15:25:56 -070089# Enable the Go compiler for these targets.
90TARGET_GO_ENABLED = (
91 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070092 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070093 'armv7a-cros-linux-gnueabihf',
Rahul Chaudhry4d416582017-10-25 12:31:58 -070094 'aarch64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070095)
96CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
97
Manoj Gupta1b5642e2017-03-08 16:44:12 -080098# Enable llvm's compiler-rt for these targets.
99TARGET_COMPILER_RT_ENABLED = (
100 'armv7a-cros-linux-gnueabi',
Yunlian Jiang1b77ee42017-10-06 13:44:29 -0700101 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -0700102 'aarch64-cros-linux-gnu',
Manoj Gupta21f3a082018-03-06 21:25:39 -0800103 'armv7m-cros-eabi',
Manoj Gupta1b5642e2017-03-08 16:44:12 -0800104)
105CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
106
Manoj Gupta946abb42017-04-12 14:27:19 -0700107TARGET_LLVM_PKGS_ENABLED = (
108 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700109 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -0700110 'aarch64-cros-linux-gnu',
Manoj Gupta93713122020-10-29 17:52:16 -0700111 'i686-pc-linux-gnu',
Manoj Gupta946abb42017-04-12 14:27:19 -0700112 'x86_64-cros-linux-gnu',
113)
114
115LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -0700116 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
117 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700118 'ex_llvm-libunwind' : ['--ex-pkg', 'sys-libs/llvm-libunwind'],
Manoj Gupta946abb42017-04-12 14:27:19 -0700119}
120
Zdenek Behan508dcce2011-12-05 15:39:32 +0100121# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
122CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500123 'binutils' : {
Manoj Guptaa91e38e2018-11-15 11:07:48 -0800124 'aarch64-cros-linux-gnu' : '-gold',
Mike Frysinger8a83c622015-05-28 00:35:05 -0400125 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800126 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700127 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500128 'i686-pc-linux-gnu' : '-gold',
129 'x86_64-cros-linux-gnu' : '-gold',
130 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100131}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100132
133
David James66a09c42012-11-05 13:31:38 -0800134class Crossdev(object):
135 """Class for interacting with crossdev and caching its output."""
136
137 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
138 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800139 # Packages that needs separate handling, in addition to what we have from
140 # crossdev.
141 MANUAL_PKGS = {
George Burgess IVca1d7612020-10-01 00:38:32 -0700142 'rust': 'dev-lang',
Han Shene23782f2016-02-18 12:20:00 -0800143 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700144 'libcxxabi': 'sys-libs',
145 'libcxx': 'sys-libs',
Yunlian Jiangda3ce5f2018-04-25 14:10:01 -0700146 'elfutils': 'dev-libs',
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700147 'llvm-libunwind': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800148 }
David James66a09c42012-11-05 13:31:38 -0800149
150 @classmethod
151 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400152 """Load crossdev cache from disk.
153
154 We invalidate the cache when crossdev updates or this script changes.
155 """
David James90239b92012-11-05 15:31:34 -0800156 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400157 # If we run the compiled/cached .pyc file, we'll read/hash that when we
158 # really always want to track the source .py file.
159 script = os.path.abspath(__file__)
160 if script.endswith('.pyc'):
161 script = script[:-1]
Mike Frysingerb3202be2019-11-15 22:25:59 -0500162 setup_toolchains_hash = hashlib.md5(
163 osutils.ReadFile(script, mode='rb')).hexdigest()
Mike Frysinger3ed47722017-08-08 14:59:08 -0400164
165 cls._CACHE = {
166 'crossdev_version': crossdev_version,
167 'setup_toolchains_hash': setup_toolchains_hash,
168 }
169
170 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
171 if reconfig:
172 logging.debug('cache: forcing regen due to reconfig')
173 return
174
175 try:
176 file_data = osutils.ReadFile(cls._CACHE_FILE)
177 except IOError as e:
178 if e.errno != errno.ENOENT:
179 logging.warning('cache: reading failed: %s', e)
180 osutils.SafeUnlink(cls._CACHE_FILE)
181 return
182
183 try:
184 data = json.loads(file_data)
185 except ValueError as e:
186 logging.warning('cache: ignoring invalid content: %s', e)
187 return
188
189 if crossdev_version != data.get('crossdev_version'):
190 logging.debug('cache: rebuilding after crossdev upgrade')
191 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
192 logging.debug('cache: rebuilding after cros_setup_toolchains change')
193 else:
194 logging.debug('cache: content is up-to-date!')
195 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800196
197 @classmethod
198 def Save(cls):
199 """Store crossdev cache on disk."""
200 # Save the cache from the successful run.
201 with open(cls._CACHE_FILE, 'w') as f:
202 json.dump(cls._CACHE, f)
203
204 @classmethod
205 def GetConfig(cls, target):
206 """Returns a map of crossdev provided variables about a tuple."""
207 CACHE_ATTR = '_target_tuple_map'
208
209 val = cls._CACHE.setdefault(CACHE_ATTR, {})
210 if not target in val:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400211 if target.startswith('host'):
Mike Frysinger66bfde52017-09-12 16:42:57 -0400212 conf = {
213 'crosspkgs': [],
214 'target': toolchain.GetHostTuple(),
215 }
Mike Frysinger785b0c32017-09-13 01:35:59 -0400216 if target == 'host':
217 packages_list = HOST_PACKAGES
218 else:
219 packages_list = HOST_POST_CROSS_PACKAGES
Mike Frysinger66bfde52017-09-12 16:42:57 -0400220 manual_pkgs = dict((pkg, cat) for cat, pkg in
Mike Frysinger785b0c32017-09-13 01:35:59 -0400221 [x.split('/') for x in packages_list])
Mike Frysinger66bfde52017-09-12 16:42:57 -0400222 else:
223 # Build the crossdev command.
224 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
225 if target in TARGET_COMPILER_RT_ENABLED:
226 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
227 if target in TARGET_GO_ENABLED:
228 cmd.extend(CROSSDEV_GO_ARGS)
229 if target in TARGET_LLVM_PKGS_ENABLED:
230 for pkg in LLVM_PKGS_TABLE:
231 cmd.extend(LLVM_PKGS_TABLE[pkg])
232 cmd.extend(['-t', target])
233 # Catch output of crossdev.
Mike Frysinger45602c72019-09-22 02:15:11 -0400234 out = cros_build_lib.run(
Mike Frysinger0282d222019-12-17 17:15:48 -0500235 cmd, print_cmd=False, stdout=True,
Mike Frysingerb3202be2019-11-15 22:25:59 -0500236 encoding='utf-8').stdout.splitlines()
Mike Frysinger66bfde52017-09-12 16:42:57 -0400237 # List of tuples split at the first '=', converted into dict.
238 conf = dict((k, cros_build_lib.ShellUnquote(v))
239 for k, v in (x.split('=', 1) for x in out))
240 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800241
Mike Frysinger66bfde52017-09-12 16:42:57 -0400242 manual_pkgs = cls.MANUAL_PKGS
243
244 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400245 conf[pkg + '_pn'] = pkg
246 conf[pkg + '_category'] = cat
247 if pkg not in conf['crosspkgs']:
248 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800249
250 val[target] = conf
251
David James66a09c42012-11-05 13:31:38 -0800252 return val[target]
253
254 @classmethod
255 def UpdateTargets(cls, targets, usepkg, config_only=False):
256 """Calls crossdev to initialize a cross target.
257
258 Args:
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000259 targets: The list of targets to initialize using crossdev.
Don Garrett25f309a2014-03-19 14:02:12 -0700260 usepkg: Copies the commandline opts.
261 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800262 """
263 configured_targets = cls._CACHE.setdefault('configured_targets', [])
264
265 cmdbase = ['crossdev', '--show-fail-log']
266 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
267 # Pick stable by default, and override as necessary.
268 cmdbase.extend(['-P', '--oneshot'])
269 if usepkg:
270 cmdbase.extend(['-P', '--getbinpkg',
271 '-P', '--usepkgonly',
272 '--without-headers'])
273
Christopher Wileyb22c0712015-06-02 10:37:03 -0700274 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800275 cmdbase.extend(['--overlays', overlays])
276 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
277
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000278 # Build target by the reversed alphabetical order to make sure
279 # armv7a-cros-linux-gnueabihf builds before armv7a-cros-linux-gnueabi
280 # because some dependency issue. This can be reverted once we
281 # migrated to armv7a-cros-linux-gnueabihf. crbug.com/711369
282 for target in sorted(targets, reverse=True):
283 if config_only and target in configured_targets:
284 continue
David James66a09c42012-11-05 13:31:38 -0800285
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000286 cmd = cmdbase + ['-t', target]
287
288 for pkg in GetTargetPackages(target):
289 if pkg == 'gdb':
290 # Gdb does not have selectable versions.
291 cmd.append('--ex-gdb')
292 elif pkg == 'ex_compiler-rt':
293 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
294 elif pkg == 'ex_go':
295 # Go does not have selectable versions.
296 cmd.extend(CROSSDEV_GO_ARGS)
297 elif pkg in LLVM_PKGS_TABLE:
298 cmd.extend(LLVM_PKGS_TABLE[pkg])
299 elif pkg in cls.MANUAL_PKGS:
300 pass
301 else:
302 # The first of the desired versions is the "primary" one.
303 version = GetDesiredPackageVersions(target, pkg)[0]
304 cmd.extend(['--%s' % pkg, version])
305
306 cmd.extend(targets[target]['crossdev'].split())
307 if config_only:
308 # In this case we want to just quietly reinit
309 cmd.append('--init-target')
Mike Frysinger0282d222019-12-17 17:15:48 -0500310 cros_build_lib.run(cmd, print_cmd=False, stdout=True)
David James66a09c42012-11-05 13:31:38 -0800311 else:
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000312 cros_build_lib.run(cmd)
David James66a09c42012-11-05 13:31:38 -0800313
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000314 configured_targets.append(target)
David James66a09c42012-11-05 13:31:38 -0800315
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100316
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100317def GetTargetPackages(target):
318 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800319 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100320 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800321 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100322
323
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100324# Portage helper functions:
325def GetPortagePackage(target, package):
326 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800327 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100328 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400329 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100330 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100331 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100332 category = conf['category']
333 # Portage package:
334 pn = conf[package + '_pn']
335 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500336 assert category
337 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100338 return '%s/%s' % (category, pn)
339
340
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700341def PortageTrees(root):
342 """Return the portage trees for a given root."""
343 if root == '/':
344 return portage.db['/']
345 # The portage logic requires the path always end in a slash.
346 root = root.rstrip('/') + '/'
347 return portage.create_trees(target_root=root, config_root=root)[root]
348
349
350def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100351 """Extracts the list of current versions of a target, package pair.
352
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500353 Args:
354 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700355 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100356
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500357 Returns:
358 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100359 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100360 versions = []
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700361 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100362 version = portage.versions.cpv_getversion(pkg)
363 versions.append(version)
364 return versions
365
366
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700367def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100368 """Extracts the current stable version for a given package.
369
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500370 Args:
371 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
372 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700373 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100374
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500375 Returns:
376 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100377 """
David James90239b92012-11-05 15:31:34 -0800378 pkgtype = 'vartree' if installed else 'porttree'
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700379 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800380 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100381
382
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700383def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384 """Resolves keywords in a given version list for a particular package.
385
386 Resolving means replacing PACKAGE_STABLE with the actual number.
387
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500388 Args:
389 target: The target to operate on (e.g. i686-pc-linux-gnu)
390 package: The target/package to operate on (e.g. gcc)
391 versions: List of versions to resolve
392 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700393 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500395 Returns:
396 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100397 """
398 resolved = []
David James90239b92012-11-05 15:31:34 -0800399 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700400 if not installed:
401 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402 for version in versions:
403 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700404 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400405 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100406 resolved.append(version)
407 return resolved
408
409
410def GetDesiredPackageVersions(target, package):
411 """Produces the list of desired versions for each target, package pair.
412
413 The first version in the list is implicitly treated as primary, ie.
414 the version that will be initialized by crossdev and selected.
415
416 If the version is PACKAGE_STABLE, it really means the current version which
417 is emerged by using the package atom with no particular version key.
418 Since crossdev unmasks all packages by default, this will actually
419 mean 'unstable' in most cases.
420
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500421 Args:
422 target: The target to operate on (e.g. i686-pc-linux-gnu)
423 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100424
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500425 Returns:
426 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100427 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400428 if package in GetTargetPackages(target):
429 return [PACKAGE_STABLE]
430 else:
431 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100432
433
434def TargetIsInitialized(target):
435 """Verifies if the given list of targets has been correctly initialized.
436
437 This determines whether we have to call crossdev while emerging
438 toolchain packages or can do it using emerge. Emerge is naturally
439 preferred, because all packages can be updated in a single pass.
440
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500441 Args:
442 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100443
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500444 Returns:
445 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100446 """
447 # Check if packages for the given target all have a proper version.
448 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100449 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800450 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100451 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400452 if not (GetStablePackageVersion(atom, True) and
453 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100454 return False
455 return True
456 except cros_build_lib.RunCommandError:
457 # Fails - The target has likely never been initialized before.
458 return False
459
460
461def RemovePackageMask(target):
462 """Removes a package.mask file for the given platform.
463
464 The pre-existing package.mask files can mess with the keywords.
465
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500466 Args:
467 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100468 """
469 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700470 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100471
472
Zdenek Behan508dcce2011-12-05 15:39:32 +0100473# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700474def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500475 """Rebuild libtool as needed
476
477 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
478 gcc, libtool will break. We can't use binary packages either as those will
479 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700480
481 Args:
482 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500483 """
484 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700485 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500486 for line in f:
487 # Look for a line like:
488 # sys_lib_search_path_spec="..."
489 # It'll be a list of paths and gcc will be one of them.
490 if line.startswith('sys_lib_search_path_spec='):
491 line = line.rstrip()
492 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400493 root_path = os.path.join(root, path.lstrip(os.path.sep))
494 logging.debug('Libtool: checking %s', root_path)
495 if not os.path.exists(root_path):
496 logging.info('Rebuilding libtool after gcc upgrade')
497 logging.info(' %s', line)
498 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500499 needs_update = True
500 break
501
502 if needs_update:
503 break
504
505 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700506 cmd = [EMERGE_CMD, '--oneshot']
507 if root != '/':
508 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
509 cmd.append('sys-devel/libtool')
Mike Frysinger45602c72019-09-22 02:15:11 -0400510 cros_build_lib.run(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400511 else:
512 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500513
514
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700515def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100516 """Determines which packages need update/unmerge and defers to portage.
517
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500518 Args:
519 targets: The list of targets to update
520 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700521 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100522 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100523 # For each target, we do two things. Figure out the list of updates,
524 # and figure out the appropriate keywords/masks. Crossdev will initialize
525 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400526 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800527 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100528 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400529 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100530 # Record the highest needed version for each target, for masking purposes.
531 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100532 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100533 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400534 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100535 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700536 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100537 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200538 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400539 if pkg in NEW_PACKAGES and usepkg:
540 # Skip this binary package (for now).
541 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100542 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400543 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400545 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100546 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400547 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800548 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100549
Mike Frysinger3bba5032016-09-20 14:15:04 -0400550 logging.info('Updating packages:')
551 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100552
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100553 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100554 if usepkg:
555 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700556 if root != '/':
557 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100558
559 cmd.extend(packages)
Mike Frysinger45602c72019-09-22 02:15:11 -0400560 cros_build_lib.run(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800561 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100562
563
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700564def CleanTargets(targets, root='/'):
565 """Unmerges old packages that are assumed unnecessary.
566
567 Args:
568 targets: The list of targets to clean up.
569 root: The install root in which we want packages cleaned up.
570 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100571 unmergemap = {}
572 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400573 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100574 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400575 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100576 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700577 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100578 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700579 # NOTE: This refers to installed packages (vartree) rather than the
580 # Portage version (porttree and/or bintree) when determining the current
581 # version. While this isn't the most accurate thing to do, it is probably
582 # a good simple compromise, which should have the desired result of
583 # uninstalling everything but the latest installed version. In
584 # particular, using the bintree (--usebinpkg) requires a non-trivial
585 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200586 desired_num = VersionListToNumeric(target, package, desired, True)
587 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400588 logging.warning('Error detecting stable version for %s, '
589 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200590 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100591 unmergemap[pkg] = set(current).difference(desired_num)
592
593 # Cleaning doesn't care about consistency and rebuilding package.* files.
594 packages = []
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400595 for pkg, vers in unmergemap.items():
Zdenek Behan508dcce2011-12-05 15:39:32 +0100596 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
597
598 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400599 logging.info('Cleaning packages:')
600 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100601 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700602 if root != '/':
603 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100604 cmd.extend(packages)
Mike Frysinger45602c72019-09-22 02:15:11 -0400605 cros_build_lib.run(cmd)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100606 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400607 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100608
609
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700610def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100611 """Runs gcc-config and binutils-config to select the desired.
612
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500613 Args:
614 targets: The targets to select
615 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700616 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100617 """
618 for package in ['gcc', 'binutils']:
619 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400620 # See if this package is part of this target.
621 if package not in GetTargetPackages(target):
622 logging.debug('%s: %s is not used', target, package)
623 continue
624
Zdenek Behan508dcce2011-12-05 15:39:32 +0100625 # Pick the first version in the numbered list as the selected one.
626 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700627 desired_num = VersionListToNumeric(target, package, desired, True,
628 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100629 desired = desired_num[0]
630 # *-config does not play revisions, strip them, keep just PV.
631 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
632
Mike Frysinger785b0c32017-09-13 01:35:59 -0400633 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100634 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800635 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100636
637 # And finally, attach target to it.
638 desired = '%s-%s' % (target, desired)
639
640 # Target specific hacks
641 if package in suffixes:
642 if target in suffixes[package]:
643 desired += suffixes[package][target]
644
David James7ec5efc2012-11-06 09:39:49 -0800645 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700646 if root != '/':
647 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800648 cmd = ['%s-config' % package, '-c', target]
Mike Frysinger45602c72019-09-22 02:15:11 -0400649 result = cros_build_lib.run(
Mike Frysinger0282d222019-12-17 17:15:48 -0500650 cmd, print_cmd=False, stdout=True, encoding='utf-8',
Mike Frysingerb3202be2019-11-15 22:25:59 -0500651 extra_env=extra_env)
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500652 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700653
654 # Do not reconfig when the current is live or nothing needs to be done.
655 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100656 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500657 cmd = [package + '-config', desired]
Mike Frysinger45602c72019-09-22 02:15:11 -0400658 cros_build_lib.run(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100659
660
Mike Frysinger35247af2012-11-16 18:58:06 -0500661def ExpandTargets(targets_wanted):
662 """Expand any possible toolchain aliases into full targets
663
664 This will expand 'all' and 'sdk' into the respective toolchain tuples.
665
666 Args:
667 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500668
Mike Frysinger35247af2012-11-16 18:58:06 -0500669 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300670 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500671 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500672 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700673 if targets_wanted == set(['boards']):
674 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300675 return {}
676
677 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500678 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300679 return all_targets
680 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500681 # Filter out all the non-sdk toolchains as we don't want to mess
682 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300683 return toolchain.FilterToolchains(all_targets, 'sdk', True)
684
685 # Verify user input.
686 nonexistent = targets_wanted.difference(all_targets)
687 if nonexistent:
Mike Frysingercd790662019-10-17 00:23:13 -0400688 raise ValueError('Invalid targets: %s' % (','.join(nonexistent),))
Gilad Arnold8195b532015-04-07 10:56:30 +0300689 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500690
691
David Jamesf8c672f2012-11-06 13:38:11 -0800692def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700693 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100694 """Performs all steps to create a synchronized toolchain enviroment.
695
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500696 Args:
697 usepkg: Use prebuilt packages
698 deleteold: Unmerge deprecated packages
699 hostonly: Only setup the host toolchain
700 reconfig: Reload crossdev config and reselect toolchains
701 targets_wanted: All the targets to update
702 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700703 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100704 """
David Jamesf8c672f2012-11-06 13:38:11 -0800705 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100706 if not hostonly:
707 # For hostonly, we can skip most of the below logic, much of which won't
708 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500709 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400710
Don Garrettc0c74002015-10-09 12:58:19 -0700711 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300712 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400713 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800714 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100715
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100716 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400717 for target in targets:
718 if TargetIsInitialized(target):
719 reconfig_targets[target] = targets[target]
720 else:
721 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100722 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400723 logging.info('The following targets need to be re-initialized:')
724 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800725 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200726 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800727 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100728
Mike Frysinger66814c32017-10-09 18:11:46 -0400729 # If we're building a subset of toolchains for a board, we might not have
730 # all the tuples that the packages expect. We don't define the "full" set
731 # of tuples currently other than "whatever the full sdk has normally".
732 if usepkg or set(('all', 'sdk')) & targets_wanted:
733 # Since we have cross-compilers now, we can update these packages.
734 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400735
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100736 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400737 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100738
739 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700740 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
741 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800742
743 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700744 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100745
Mike Frysingerc880a962013-11-08 13:59:06 -0500746 # Now that we've cleared out old versions, see if we need to rebuild
747 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700748 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500749
Zdenek Behan508dcce2011-12-05 15:39:32 +0100750
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700751def ShowConfig(name):
752 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500753
754 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700755 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500756 """
Don Garrettc0c74002015-10-09 12:58:19 -0700757 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500758 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400759 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400760 print(','.join(
Mike Frysinger818d9632019-08-24 14:43:05 -0400761 list(toolchain.FilterToolchains(toolchains, 'default', True)) +
762 list(toolchain.FilterToolchains(toolchains, 'default', False))))
Mike Frysinger35247af2012-11-16 18:58:06 -0500763
764
Mike Frysinger35247af2012-11-16 18:58:06 -0500765def GeneratePathWrapper(root, wrappath, path):
766 """Generate a shell script to execute another shell script
767
768 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
769 argv[0] won't be pointing to the correct path, generate a shell script that
770 just executes another program with its full path.
771
772 Args:
773 root: The root tree to generate scripts inside of
774 wrappath: The full path (inside |root|) to create the wrapper
775 path: The target program which this wrapper will execute
776 """
777 replacements = {
778 'path': path,
779 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
780 }
Takuto Ikuta58403972018-08-16 18:52:51 +0900781
782 # Do not use exec here, because exec invokes script with absolute path in
783 # argv0. Keeping relativeness allows us to remove abs path from compile result
784 # and leads directory independent build cache sharing in some distributed
785 # build system.
Mike Frysinger35247af2012-11-16 18:58:06 -0500786 wrapper = """#!/bin/sh
Takuto Ikuta58403972018-08-16 18:52:51 +0900787basedir=$(dirname "$0")
788"${basedir}/%(relroot)s%(path)s" "$@"
789exit "$?"
Mike Frysinger35247af2012-11-16 18:58:06 -0500790""" % replacements
791 root_wrapper = root + wrappath
792 if os.path.islink(root_wrapper):
793 os.unlink(root_wrapper)
794 else:
795 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
796 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400797 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500798
799
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700800def FixClangXXWrapper(root, path):
801 """Fix wrapper shell scripts and symlinks for invoking clang++
802
803 In a typical installation, clang++ symlinks to clang, which symlinks to the
804 elf executable. The executable distinguishes between clang and clang++ based
805 on argv[0].
806
807 When invoked through the LdsoWrapper, argv[0] always contains the path to the
808 executable elf file, making clang/clang++ invocations indistinguishable.
809
810 This function detects if the elf executable being wrapped is clang-X.Y, and
811 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
812
813 The calling sequence now becomes:
814 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
815 the Ldsowrapper).
816 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
817 to the original clang-3.9 elf.
818 -) The difference this time is that inside the elf file execution, $0 is
819 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
820
Manoj Guptaae268142018-04-27 23:28:36 -0700821 Update: Starting since clang 7, the clang and clang++ are symlinks to
822 clang-7 binary, not clang-7.0. The pattern match is extended to handle
823 both clang-7 and clang-7.0 cases for now. (https://crbug.com/837889)
824
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700825 Args:
826 root: The root tree to generate scripts / symlinks inside of
827 path: The target elf for which LdsoWrapper was created
828 """
Manoj Guptaae268142018-04-27 23:28:36 -0700829 if re.match(r'/usr/bin/clang-\d+(\.\d+)*$', path):
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700830 logging.info('fixing clang++ invocation for %s', path)
831 clangdir = os.path.dirname(root + path)
832 clang = os.path.basename(path)
833 clangxx = clang.replace('clang', 'clang++')
834
835 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
836 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
837
838 # Create a hardlink clang++-X.Y pointing to clang-X.Y
839 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
840
841 # Adjust the clang++ symlink to point to clang++-X.Y
842 os.unlink(os.path.join(clangdir, 'clang++'))
843 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
844
845
Mike Frysinger35247af2012-11-16 18:58:06 -0500846def FileIsCrosSdkElf(elf):
847 """Determine if |elf| is an ELF that we execute in the cros_sdk
848
849 We don't need this to be perfect, just quick. It makes sure the ELF
850 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
851
852 Args:
853 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500854
Mike Frysinger35247af2012-11-16 18:58:06 -0500855 Returns:
856 True if we think |elf| is a native ELF
857 """
Mike Frysinger4a12bf12019-12-04 04:20:10 -0500858 with open(elf, 'rb') as f:
Mike Frysinger35247af2012-11-16 18:58:06 -0500859 data = f.read(20)
860 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
Mike Frysinger4a12bf12019-12-04 04:20:10 -0500861 return (data[0:4] == b'\x7fELF' and
Mike Frysingerdd34dfe2019-12-10 16:25:47 -0500862 data[4:5] == b'\x02' and
863 data[5:6] == b'\x01' and
864 data[18:19] == b'\x3e')
Mike Frysinger35247af2012-11-16 18:58:06 -0500865
866
867def IsPathPackagable(ptype, path):
868 """Should the specified file be included in a toolchain package?
869
870 We only need to handle files as we'll create dirs as we need them.
871
872 Further, trim files that won't be useful:
873 - non-english translations (.mo) since it'd require env vars
874 - debug files since these are for the host compiler itself
875 - info/man pages as they're big, and docs are online, and the
876 native docs should work fine for the most part (`man gcc`)
877
878 Args:
879 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
880 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500881
Mike Frysinger35247af2012-11-16 18:58:06 -0500882 Returns:
883 True if we want to include this path in the package
884 """
885 return not (ptype in ('dir',) or
886 path.startswith('/usr/lib/debug/') or
887 os.path.splitext(path)[1] == '.mo' or
888 ('/man/' in path or '/info/' in path))
889
890
891def ReadlinkRoot(path, root):
892 """Like os.readlink(), but relative to a |root|
893
894 Args:
895 path: The symlink to read
896 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500897
Mike Frysinger35247af2012-11-16 18:58:06 -0500898 Returns:
899 A fully resolved symlink path
900 """
901 while os.path.islink(root + path):
902 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
903 return path
904
905
906def _GetFilesForTarget(target, root='/'):
907 """Locate all the files to package for |target|
908
909 This does not cover ELF dependencies.
910
911 Args:
912 target: The toolchain target name
913 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500914
Mike Frysinger35247af2012-11-16 18:58:06 -0500915 Returns:
916 A tuple of a set of all packable paths, and a set of all paths which
917 are also native ELFs
918 """
919 paths = set()
920 elfs = set()
921
922 # Find all the files owned by the packages for this target.
923 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500924
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700925 # Skip Go compiler from redistributable packages.
926 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
927 # into it. Due to this, the toolchain cannot be unpacked anywhere
928 # else and be readily useful. To enable packaging Go, we need to:
929 # -) Tweak the wrappers/environment to override GOROOT
930 # automatically based on the unpack location.
931 # -) Make sure the ELF dependency checking and wrapping logic
932 # below skips the Go toolchain executables and libraries.
933 # -) Make sure the packaging process maintains the relative
934 # timestamps of precompiled standard library packages.
935 # (see dev-lang/go ebuild for details).
936 if pkg == 'ex_go':
937 continue
938
Yunlian Jiang36f35242018-04-27 10:18:40 -0700939 # Use armv7a-cros-linux-gnueabi/compiler-rt for
940 # armv7a-cros-linux-gnueabihf/compiler-rt.
941 # Currently the armv7a-cros-linux-gnueabi is actually
942 # the same as armv7a-cros-linux-gnueabihf with different names.
943 # Because of that, for compiler-rt, it generates the same binary in
944 # the same location. To avoid the installation conflict, we do not
945 # install anything for 'armv7a-cros-linux-gnueabihf'. This would cause
946 # problem if other people try to use standalone armv7a-cros-linux-gnueabihf
947 # toolchain.
948 if 'compiler-rt' in pkg and 'armv7a-cros-linux-gnueabi' in target:
949 atom = GetPortagePackage(target, pkg)
950 cat, pn = atom.split('/')
951 ver = GetInstalledPackageVersions(atom, root=root)[0]
Yunlian Jiang36f35242018-04-27 10:18:40 -0700952 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
953 settings=portage.settings)
954 contents = dblink.getcontents()
955 if not contents:
956 if 'hf' in target:
957 new_target = 'armv7a-cros-linux-gnueabi'
958 else:
959 new_target = 'armv7a-cros-linux-gnueabihf'
960 atom = GetPortagePackage(new_target, pkg)
961 else:
962 atom = GetPortagePackage(target, pkg)
963
Mike Frysinger35247af2012-11-16 18:58:06 -0500964 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700965 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700966 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500967
Mike Frysinger35247af2012-11-16 18:58:06 -0500968 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
969 settings=portage.settings)
970 contents = dblink.getcontents()
971 for obj in contents:
972 ptype = contents[obj][0]
973 if not IsPathPackagable(ptype, obj):
974 continue
975
976 if ptype == 'obj':
977 # For native ELFs, we need to pull in their dependencies too.
978 if FileIsCrosSdkElf(obj):
Mike Frysinger60a2f6c2019-12-04 04:18:58 -0500979 logging.debug('Adding ELF %s', obj)
Mike Frysinger35247af2012-11-16 18:58:06 -0500980 elfs.add(obj)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -0500981 logging.debug('Adding path %s', obj)
Mike Frysinger35247af2012-11-16 18:58:06 -0500982 paths.add(obj)
983
984 return paths, elfs
985
986
987def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500988 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500989 """Link in all packable files and their runtime dependencies
990
991 This also wraps up executable ELFs with helper scripts.
992
993 Args:
994 output_dir: The output directory to store files
995 paths: All the files to include
996 elfs: All the files which are ELFs (a subset of |paths|)
997 ldpaths: A dict of static ldpath information
998 path_rewrite_func: User callback to rewrite paths in output_dir
999 root: The root path to pull all packages/files from
1000 """
1001 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -04001002 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -05001003 for path in paths:
1004 new_path = path_rewrite_func(path)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001005 logging.debug('Transformed %s to %s', path, new_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001006 dst = output_dir + new_path
1007 osutils.SafeMakedirs(os.path.dirname(dst))
1008
1009 # Is this a symlink which we have to rewrite or wrap?
1010 # Delay wrap check until after we have created all paths.
1011 src = root + path
1012 if os.path.islink(src):
1013 tgt = os.readlink(src)
1014 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -04001015 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -05001016
1017 # Rewrite absolute links to relative and then generate the symlink
1018 # ourselves. All other symlinks can be hardlinked below.
1019 if tgt[0] == '/':
1020 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
1021 os.symlink(tgt, dst)
1022 continue
1023
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001024 logging.debug('Linking path %s -> %s', src, dst)
Mike Frysinger35247af2012-11-16 18:58:06 -05001025 os.link(src, dst)
1026
Mike Frysinger35247af2012-11-16 18:58:06 -05001027 # Locate all the dependencies for all the ELFs. Stick them all in the
1028 # top level "lib" dir to make the wrapper simpler. This exact path does
1029 # not matter since we execute ldso directly, and we tell the ldso the
1030 # exact path to search for its libraries.
1031 libdir = os.path.join(output_dir, 'lib')
1032 osutils.SafeMakedirs(libdir)
1033 donelibs = set()
Mike Frysinger9fe02342019-12-12 17:52:53 -05001034 basenamelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -04001035 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -05001036 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -04001037 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001038 logging.debug('Parsed elf %s data: %s', elf, e)
Mike Frysinger35247af2012-11-16 18:58:06 -05001039 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -07001040 # Do not create wrapper for libc. crbug.com/766827
1041 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -05001042 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -04001043 interp = os.path.join('/lib', os.path.basename(interp))
1044 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
1045 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -07001046 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -05001047
Mike Frysinger221bd822017-09-29 02:51:47 -04001048 # Wrap any symlinks to the wrapper.
1049 if elf in sym_paths:
1050 link = sym_paths[elf]
1051 GeneratePathWrapper(output_dir, link, elf)
1052
Mike Frysinger9fe02342019-12-12 17:52:53 -05001053 # TODO(crbug.com/917193): Drop this hack once libopcodes linkage is fixed.
1054 if os.path.basename(elf).startswith('libopcodes-'):
1055 continue
Mike Frysinger35247af2012-11-16 18:58:06 -05001056
Mike Frysinger9fe02342019-12-12 17:52:53 -05001057 for lib, lib_data in e['libs'].items():
Mike Frysinger35247af2012-11-16 18:58:06 -05001058 src = path = lib_data['path']
1059 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001060 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001061 continue
Mike Frysinger9fe02342019-12-12 17:52:53 -05001062
1063 # No need to try and copy the same source lib multiple times.
1064 if path in donelibs:
1065 continue
1066 donelibs.add(path)
1067
1068 # Die if we try to normalize different source libs with the same basename.
1069 if lib in basenamelibs:
1070 logging.error('Multiple sources detected for %s:\n new: %s\n old: %s',
1071 os.path.join('/lib', lib), path,
1072 ' '.join(x for x in donelibs
1073 if x != path and os.path.basename(x) == lib))
1074 # TODO(crbug.com/917193): Make this fatal.
1075 # cros_build_lib.Die('Unable to resolve lib conflicts')
1076 continue
1077 basenamelibs.add(lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001078
1079 # Needed libs are the SONAME, but that is usually a symlink, not a
1080 # real file. So link in the target rather than the symlink itself.
1081 # We have to walk all the possible symlinks (SONAME could point to a
1082 # symlink which points to a symlink), and we have to handle absolute
1083 # ourselves (since we have a "root" argument).
1084 dst = os.path.join(libdir, os.path.basename(path))
1085 src = ReadlinkRoot(src, root)
1086
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001087 logging.debug('Linking lib %s -> %s', root + src, dst)
Mike Frysinger35247af2012-11-16 18:58:06 -05001088 os.link(root + src, dst)
1089
1090
1091def _EnvdGetVar(envd, var):
1092 """Given a Gentoo env.d file, extract a var from it
1093
1094 Args:
1095 envd: The env.d file to load (may be a glob path)
1096 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001097
Mike Frysinger35247af2012-11-16 18:58:06 -05001098 Returns:
1099 The value of |var|
1100 """
1101 envds = glob.glob(envd)
1102 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1103 envd = envds[0]
Mike Frysingere652ba12019-09-08 00:57:43 -04001104 return key_value_store.LoadFile(envd)[var]
Mike Frysinger35247af2012-11-16 18:58:06 -05001105
1106
1107def _ProcessBinutilsConfig(target, output_dir):
1108 """Do what binutils-config would have done"""
1109 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001110
1111 # Locate the bin dir holding the gold linker.
1112 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1113 target, 'binutils-bin')
1114 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001115 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001116 if not srcpath:
1117 # Maybe this target doesn't support gold.
1118 globpath = os.path.join(binutils_bin_path, '*')
1119 srcpath = glob.glob(globpath)
1120 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1121 % globpath)
1122 srcpath = srcpath[0]
1123 ld_path = os.path.join(srcpath, 'ld')
1124 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1125 ld_path = os.path.join(srcpath, 'ld.bfd')
1126 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1127 ld_path = os.path.join(srcpath, 'ld.gold')
1128 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1129 % ld_path)
1130
1131 # Nope, no gold support to be found.
1132 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001133 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001134 else:
1135 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001136 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001137
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001138 # Package the binutils-bin directory without the '-gold' suffix
1139 # if gold is not enabled as the default linker for this target.
1140 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1141 if not gold_supported:
1142 srcpath = srcpath[:-len('-gold')]
1143 ld_path = os.path.join(srcpath, 'ld')
1144 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1145
Mike Frysinger78b7a812014-11-26 19:45:23 -05001146 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001147 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1148 for prog in os.listdir(output_dir + srcpath):
1149 # Skip binaries already wrapped.
1150 if not prog.endswith('.real'):
1151 GeneratePathWrapper(output_dir, binpath + prog,
1152 os.path.join(srcpath, prog))
1153 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1154 os.path.join(srcpath, prog))
1155
David James27ac4ae2012-12-03 23:16:15 -08001156 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001157 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1158 if gold_supported:
1159 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001160 else:
1161 # If gold is not enabled as the default linker and 2 env.d
1162 # files exist, pick the one without the '-gold' suffix.
1163 envds = sorted(glob.glob(envd))
1164 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1165 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001166 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1167 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1168 output_dir + libpath)
1169
1170
1171def _ProcessGccConfig(target, output_dir):
1172 """Do what gcc-config would have done"""
1173 binpath = '/bin'
1174 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1175 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1176 for prog in os.listdir(output_dir + srcpath):
1177 # Skip binaries already wrapped.
1178 if (not prog.endswith('.real') and
1179 not prog.endswith('.elf') and
1180 prog.startswith(target)):
1181 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1182 os.path.join(srcpath, prog))
1183 return srcpath
1184
1185
Frank Henigman179ec7c2015-02-06 03:01:09 -05001186def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1187 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001188 # Disable ccache since we know it won't work outside of chroot.
Tobias Boschddd16492019-08-14 09:29:54 -07001189
Tobias Boschddd16492019-08-14 09:29:54 -07001190 # Use the version of the wrapper that does not use ccache.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001191 for sysroot_wrapper in glob.glob(os.path.join(
Tobias Boschddd16492019-08-14 09:29:54 -07001192 output_dir + srcpath, 'sysroot_wrapper*.ccache')):
1193 # Can't update the wrapper in place to not affect the chroot,
1194 # but only the extracted toolchain.
1195 os.unlink(sysroot_wrapper)
1196 shutil.copy(sysroot_wrapper[:-6] + 'noccache', sysroot_wrapper)
Tobias Bosch7bc907a2019-10-09 11:52:40 -07001197 shutil.copy(sysroot_wrapper[:-6] + 'noccache.elf', sysroot_wrapper + '.elf')
Mike Frysinger35247af2012-11-16 18:58:06 -05001198
1199
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001200def _CreateMainLibDir(target, output_dir):
1201 """Create some lib dirs so that compiler can get the right Gcc paths"""
1202 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1203 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1204
1205
Mike Frysinger35247af2012-11-16 18:58:06 -05001206def _ProcessDistroCleanups(target, output_dir):
1207 """Clean up the tree and remove all distro-specific requirements
1208
1209 Args:
1210 target: The toolchain target name
1211 output_dir: The output directory to clean up
1212 """
1213 _ProcessBinutilsConfig(target, output_dir)
1214 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001215 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001216 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001217
1218 osutils.RmDir(os.path.join(output_dir, 'etc'))
1219
1220
1221def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1222 """Setup a tree from the packages for the specified target
1223
1224 This populates a path with all the files from toolchain packages so that
1225 a tarball can easily be generated from the result.
1226
1227 Args:
1228 target: The target to create a packagable root from
1229 output_dir: The output directory to place all the files
1230 ldpaths: A dict of static ldpath information
1231 root: The root path to pull all packages/files from
1232 """
1233 # Find all the files owned by the packages for this target.
1234 paths, elfs = _GetFilesForTarget(target, root=root)
1235
1236 # Link in all the package's files, any ELF dependencies, and wrap any
1237 # executable ELFs with helper scripts.
1238 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001239 """Move /usr/bin to /bin so people can just use that toplevel dir
1240
George Burgess IVca1d7612020-10-01 00:38:32 -07001241 Note we do not apply this to clang or rust - there is correlation between
1242 clang's search path for libraries / inclusion and its installation path.
Han Shen699ea192016-03-02 10:42:47 -08001243 """
George Burgess IVca1d7612020-10-01 00:38:32 -07001244 if (path.startswith('/usr/bin/') and
1245 not any(x in path for x in ('clang', 'rust', 'cargo'))):
Han Shen699ea192016-03-02 10:42:47 -08001246 return path[4:]
1247 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001248 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1249 path_rewrite_func=MoveUsrBinToBin, root=root)
1250
1251 # The packages, when part of the normal distro, have helper scripts
1252 # that setup paths and such. Since we are making this standalone, we
1253 # need to preprocess all that ourselves.
1254 _ProcessDistroCleanups(target, output_dir)
1255
1256
1257def CreatePackages(targets_wanted, output_dir, root='/'):
1258 """Create redistributable cross-compiler packages for the specified targets
1259
1260 This creates toolchain packages that should be usable in conjunction with
1261 a downloaded sysroot (created elsewhere).
1262
1263 Tarballs (one per target) will be created in $PWD.
1264
1265 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001266 targets_wanted: The targets to package up.
1267 output_dir: The directory to put the packages in.
1268 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001269 """
Ralph Nathan03047282015-03-23 11:09:32 -07001270 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001271 osutils.SafeMakedirs(output_dir)
1272 ldpaths = lddtree.LoadLdpaths(root)
1273 targets = ExpandTargets(targets_wanted)
1274
Mike Frysinger221bd822017-09-29 02:51:47 -04001275 with osutils.TempDir(prefix='create-packages') as tempdir:
1276 logging.debug('Using tempdir: %s', tempdir)
1277
Mike Frysinger35247af2012-11-16 18:58:06 -05001278 # We have to split the root generation from the compression stages. This is
1279 # because we hardlink in all the files (to avoid overhead of reading/writing
1280 # the copies multiple times). But tar gets angry if a file's hardlink count
1281 # changes from when it starts reading a file to when it finishes.
1282 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1283 for target in targets:
1284 output_target_dir = os.path.join(tempdir, target)
1285 queue.put([target, output_target_dir, ldpaths, root])
1286
1287 # Build the tarball.
1288 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1289 for target in targets:
1290 tar_file = os.path.join(output_dir, target + '.tar.xz')
1291 queue.put([tar_file, os.path.join(tempdir, target)])
1292
1293
Mike Frysinger07534cf2017-09-12 17:40:21 -04001294def GetParser():
1295 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001296 parser = commandline.ArgumentParser(description=__doc__)
1297 parser.add_argument('-u', '--nousepkg',
1298 action='store_false', dest='usepkg', default=True,
1299 help='Use prebuilt packages if possible')
1300 parser.add_argument('-d', '--deleteold',
1301 action='store_true', dest='deleteold', default=False,
1302 help='Unmerge deprecated packages')
1303 parser.add_argument('-t', '--targets',
1304 dest='targets', default='sdk',
Mike Frysinger80de5012019-08-01 14:10:53 -04001305 help='Comma separated list of tuples. Special keywords '
Don Garrettc0c74002015-10-09 12:58:19 -07001306 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001307 "allowed. Defaults to 'sdk'.")
1308 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1309 help='Comma separated list of boards whose toolchains we '
1310 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001311 parser.add_argument('--hostonly',
1312 dest='hostonly', default=False, action='store_true',
1313 help='Only setup the host toolchain. '
1314 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001315 parser.add_argument('--show-board-cfg', '--show-cfg',
1316 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001317 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001318 parser.add_argument('--show-packages', default=None,
1319 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001320 parser.add_argument('--create-packages',
1321 action='store_true', default=False,
1322 help='Build redistributable packages')
1323 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1324 help='Output directory')
1325 parser.add_argument('--reconfig', default=False, action='store_true',
1326 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001327 parser.add_argument('--sysroot', type='path',
1328 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001329 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001330
Mike Frysinger07534cf2017-09-12 17:40:21 -04001331
1332def main(argv):
1333 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001334 options = parser.parse_args(argv)
1335 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001336
Mike Frysinger35247af2012-11-16 18:58:06 -05001337 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001338 conflicting_options = (
1339 options.cfg_name,
1340 options.show_packages,
1341 options.create_packages,
1342 )
1343 if sum(bool(x) for x in conflicting_options) > 1:
1344 parser.error('conflicting options: create-packages & show-packages & '
1345 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001346
Gilad Arnold8195b532015-04-07 10:56:30 +03001347 targets_wanted = set(options.targets.split(','))
1348 boards_wanted = (set(options.include_boards.split(','))
1349 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001350
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001351 if options.cfg_name:
1352 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001353 elif options.show_packages is not None:
1354 cros_build_lib.AssertInsideChroot()
1355 target = options.show_packages
1356 Crossdev.Load(False)
1357 for package in GetTargetPackages(target):
1358 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001359 elif options.create_packages:
1360 cros_build_lib.AssertInsideChroot()
1361 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001362 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001363 else:
1364 cros_build_lib.AssertInsideChroot()
1365 # This has to be always run as root.
1366 if os.geteuid() != 0:
1367 cros_build_lib.Die('this script must be run as root')
1368
1369 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001370 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001371 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001372 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001373 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001374 Crossdev.Save()
1375
1376 return 0