blob: 71d9d5736b2703c04d274ae88a30bed90b319ff3 [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 = {}
ChromeOS Developereb8a5c42021-01-12 00:05:02 +0000528 # Used to keep track of post-cross packages. These are allowed to have
529 # implicit dependencies on toolchain packages, and therefore need to
530 # be built last.
531 post_cross_pkgs = set()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100532 for target in targets:
ChromeOS Developereb8a5c42021-01-12 00:05:02 +0000533 is_post_cross_target = target.endswith('-post-cross')
Mike Frysinger3bba5032016-09-20 14:15:04 -0400534 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100535 # Record the highest needed version for each target, for masking purposes.
536 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100537 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100538 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400539 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100540 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700541 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200543 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400544 if pkg in NEW_PACKAGES and usepkg:
545 # Skip this binary package (for now).
546 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100547 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400548 logging.debug(' %s -> %s', current, desired_num)
ChromeOS Developereb8a5c42021-01-12 00:05:02 +0000549 if is_post_cross_target:
550 post_cross_pkgs.add(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100551
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400552 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100553 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400554 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800555 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100556
Mike Frysinger3bba5032016-09-20 14:15:04 -0400557 logging.info('Updating packages:')
558 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100559
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100560 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100561 if usepkg:
562 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700563 if root != '/':
564 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100565
ChromeOS Developereb8a5c42021-01-12 00:05:02 +0000566 if usepkg:
567 # Since we are not building from source, we can handle
568 # all packages in one go.
569 cmd.extend(packages)
570 cros_build_lib.run(cmd)
571 else:
572 post_cross_cmd = cmd[:]
573 cmd.extend([pkg for pkg in packages if pkg not in post_cross_pkgs])
574 cros_build_lib.run(cmd)
575 post_cross_items = [pkg for pkg in packages if pkg in post_cross_pkgs]
576 if len(post_cross_items) > 0:
577 cros_build_lib.run(post_cross_cmd + post_cross_items)
David Jamesf8c672f2012-11-06 13:38:11 -0800578 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100579
580
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700581def CleanTargets(targets, root='/'):
582 """Unmerges old packages that are assumed unnecessary.
583
584 Args:
585 targets: The list of targets to clean up.
586 root: The install root in which we want packages cleaned up.
587 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100588 unmergemap = {}
589 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400590 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100591 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400592 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100593 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700594 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100595 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700596 # NOTE: This refers to installed packages (vartree) rather than the
597 # Portage version (porttree and/or bintree) when determining the current
598 # version. While this isn't the most accurate thing to do, it is probably
599 # a good simple compromise, which should have the desired result of
600 # uninstalling everything but the latest installed version. In
601 # particular, using the bintree (--usebinpkg) requires a non-trivial
602 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200603 desired_num = VersionListToNumeric(target, package, desired, True)
604 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400605 logging.warning('Error detecting stable version for %s, '
606 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200607 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100608 unmergemap[pkg] = set(current).difference(desired_num)
609
610 # Cleaning doesn't care about consistency and rebuilding package.* files.
611 packages = []
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400612 for pkg, vers in unmergemap.items():
Zdenek Behan508dcce2011-12-05 15:39:32 +0100613 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
614
615 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400616 logging.info('Cleaning packages:')
617 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100618 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700619 if root != '/':
620 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100621 cmd.extend(packages)
Mike Frysinger45602c72019-09-22 02:15:11 -0400622 cros_build_lib.run(cmd)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100623 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400624 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100625
626
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700627def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100628 """Runs gcc-config and binutils-config to select the desired.
629
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500630 Args:
631 targets: The targets to select
632 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700633 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100634 """
635 for package in ['gcc', 'binutils']:
636 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400637 # See if this package is part of this target.
638 if package not in GetTargetPackages(target):
639 logging.debug('%s: %s is not used', target, package)
640 continue
641
Zdenek Behan508dcce2011-12-05 15:39:32 +0100642 # Pick the first version in the numbered list as the selected one.
643 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700644 desired_num = VersionListToNumeric(target, package, desired, True,
645 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100646 desired = desired_num[0]
647 # *-config does not play revisions, strip them, keep just PV.
648 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
649
Mike Frysinger785b0c32017-09-13 01:35:59 -0400650 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100651 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800652 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100653
654 # And finally, attach target to it.
655 desired = '%s-%s' % (target, desired)
656
657 # Target specific hacks
658 if package in suffixes:
659 if target in suffixes[package]:
660 desired += suffixes[package][target]
661
David James7ec5efc2012-11-06 09:39:49 -0800662 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700663 if root != '/':
664 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800665 cmd = ['%s-config' % package, '-c', target]
Mike Frysinger45602c72019-09-22 02:15:11 -0400666 result = cros_build_lib.run(
Mike Frysinger0282d222019-12-17 17:15:48 -0500667 cmd, print_cmd=False, stdout=True, encoding='utf-8',
Mike Frysingerb3202be2019-11-15 22:25:59 -0500668 extra_env=extra_env)
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500669 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700670
671 # Do not reconfig when the current is live or nothing needs to be done.
672 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100673 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500674 cmd = [package + '-config', desired]
Mike Frysinger45602c72019-09-22 02:15:11 -0400675 cros_build_lib.run(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100676
677
Mike Frysinger35247af2012-11-16 18:58:06 -0500678def ExpandTargets(targets_wanted):
679 """Expand any possible toolchain aliases into full targets
680
681 This will expand 'all' and 'sdk' into the respective toolchain tuples.
682
683 Args:
684 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500685
Mike Frysinger35247af2012-11-16 18:58:06 -0500686 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300687 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500688 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500689 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700690 if targets_wanted == set(['boards']):
691 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300692 return {}
693
694 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500695 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300696 return all_targets
697 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500698 # Filter out all the non-sdk toolchains as we don't want to mess
699 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300700 return toolchain.FilterToolchains(all_targets, 'sdk', True)
701
702 # Verify user input.
703 nonexistent = targets_wanted.difference(all_targets)
704 if nonexistent:
Mike Frysingercd790662019-10-17 00:23:13 -0400705 raise ValueError('Invalid targets: %s' % (','.join(nonexistent),))
Gilad Arnold8195b532015-04-07 10:56:30 +0300706 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500707
708
David Jamesf8c672f2012-11-06 13:38:11 -0800709def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700710 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100711 """Performs all steps to create a synchronized toolchain enviroment.
712
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500713 Args:
714 usepkg: Use prebuilt packages
715 deleteold: Unmerge deprecated packages
716 hostonly: Only setup the host toolchain
717 reconfig: Reload crossdev config and reselect toolchains
718 targets_wanted: All the targets to update
719 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700720 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100721 """
David Jamesf8c672f2012-11-06 13:38:11 -0800722 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100723 if not hostonly:
724 # For hostonly, we can skip most of the below logic, much of which won't
725 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500726 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400727
Don Garrettc0c74002015-10-09 12:58:19 -0700728 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300729 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400730 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800731 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100732
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100733 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400734 for target in targets:
735 if TargetIsInitialized(target):
736 reconfig_targets[target] = targets[target]
737 else:
738 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100739 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400740 logging.info('The following targets need to be re-initialized:')
741 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800742 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200743 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800744 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100745
Mike Frysinger66814c32017-10-09 18:11:46 -0400746 # If we're building a subset of toolchains for a board, we might not have
747 # all the tuples that the packages expect. We don't define the "full" set
748 # of tuples currently other than "whatever the full sdk has normally".
749 if usepkg or set(('all', 'sdk')) & targets_wanted:
750 # Since we have cross-compilers now, we can update these packages.
751 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400752
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100753 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400754 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100755
756 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700757 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
758 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800759
760 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700761 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100762
Mike Frysingerc880a962013-11-08 13:59:06 -0500763 # Now that we've cleared out old versions, see if we need to rebuild
764 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700765 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500766
Zdenek Behan508dcce2011-12-05 15:39:32 +0100767
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700768def ShowConfig(name):
769 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500770
771 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700772 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500773 """
Don Garrettc0c74002015-10-09 12:58:19 -0700774 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500775 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400776 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400777 print(','.join(
Mike Frysinger818d9632019-08-24 14:43:05 -0400778 list(toolchain.FilterToolchains(toolchains, 'default', True)) +
779 list(toolchain.FilterToolchains(toolchains, 'default', False))))
Mike Frysinger35247af2012-11-16 18:58:06 -0500780
781
Mike Frysinger35247af2012-11-16 18:58:06 -0500782def GeneratePathWrapper(root, wrappath, path):
783 """Generate a shell script to execute another shell script
784
785 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
786 argv[0] won't be pointing to the correct path, generate a shell script that
787 just executes another program with its full path.
788
789 Args:
790 root: The root tree to generate scripts inside of
791 wrappath: The full path (inside |root|) to create the wrapper
792 path: The target program which this wrapper will execute
793 """
794 replacements = {
795 'path': path,
796 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
797 }
Takuto Ikuta58403972018-08-16 18:52:51 +0900798
799 # Do not use exec here, because exec invokes script with absolute path in
800 # argv0. Keeping relativeness allows us to remove abs path from compile result
801 # and leads directory independent build cache sharing in some distributed
802 # build system.
Mike Frysinger35247af2012-11-16 18:58:06 -0500803 wrapper = """#!/bin/sh
Takuto Ikuta58403972018-08-16 18:52:51 +0900804basedir=$(dirname "$0")
805"${basedir}/%(relroot)s%(path)s" "$@"
806exit "$?"
Mike Frysinger35247af2012-11-16 18:58:06 -0500807""" % replacements
808 root_wrapper = root + wrappath
809 if os.path.islink(root_wrapper):
810 os.unlink(root_wrapper)
811 else:
812 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
813 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400814 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500815
816
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700817def FixClangXXWrapper(root, path):
818 """Fix wrapper shell scripts and symlinks for invoking clang++
819
820 In a typical installation, clang++ symlinks to clang, which symlinks to the
821 elf executable. The executable distinguishes between clang and clang++ based
822 on argv[0].
823
824 When invoked through the LdsoWrapper, argv[0] always contains the path to the
825 executable elf file, making clang/clang++ invocations indistinguishable.
826
827 This function detects if the elf executable being wrapped is clang-X.Y, and
828 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
829
830 The calling sequence now becomes:
831 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
832 the Ldsowrapper).
833 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
834 to the original clang-3.9 elf.
835 -) The difference this time is that inside the elf file execution, $0 is
836 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
837
Manoj Guptaae268142018-04-27 23:28:36 -0700838 Update: Starting since clang 7, the clang and clang++ are symlinks to
839 clang-7 binary, not clang-7.0. The pattern match is extended to handle
840 both clang-7 and clang-7.0 cases for now. (https://crbug.com/837889)
841
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700842 Args:
843 root: The root tree to generate scripts / symlinks inside of
844 path: The target elf for which LdsoWrapper was created
845 """
Manoj Guptaae268142018-04-27 23:28:36 -0700846 if re.match(r'/usr/bin/clang-\d+(\.\d+)*$', path):
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700847 logging.info('fixing clang++ invocation for %s', path)
848 clangdir = os.path.dirname(root + path)
849 clang = os.path.basename(path)
850 clangxx = clang.replace('clang', 'clang++')
851
852 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
853 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
854
855 # Create a hardlink clang++-X.Y pointing to clang-X.Y
856 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
857
858 # Adjust the clang++ symlink to point to clang++-X.Y
859 os.unlink(os.path.join(clangdir, 'clang++'))
860 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
861
862
Mike Frysinger35247af2012-11-16 18:58:06 -0500863def FileIsCrosSdkElf(elf):
864 """Determine if |elf| is an ELF that we execute in the cros_sdk
865
866 We don't need this to be perfect, just quick. It makes sure the ELF
867 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
868
869 Args:
870 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500871
Mike Frysinger35247af2012-11-16 18:58:06 -0500872 Returns:
873 True if we think |elf| is a native ELF
874 """
Mike Frysinger4a12bf12019-12-04 04:20:10 -0500875 with open(elf, 'rb') as f:
Mike Frysinger35247af2012-11-16 18:58:06 -0500876 data = f.read(20)
877 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
Mike Frysinger4a12bf12019-12-04 04:20:10 -0500878 return (data[0:4] == b'\x7fELF' and
Mike Frysingerdd34dfe2019-12-10 16:25:47 -0500879 data[4:5] == b'\x02' and
880 data[5:6] == b'\x01' and
881 data[18:19] == b'\x3e')
Mike Frysinger35247af2012-11-16 18:58:06 -0500882
883
884def IsPathPackagable(ptype, path):
885 """Should the specified file be included in a toolchain package?
886
887 We only need to handle files as we'll create dirs as we need them.
888
889 Further, trim files that won't be useful:
890 - non-english translations (.mo) since it'd require env vars
891 - debug files since these are for the host compiler itself
892 - info/man pages as they're big, and docs are online, and the
893 native docs should work fine for the most part (`man gcc`)
894
895 Args:
896 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
897 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500898
Mike Frysinger35247af2012-11-16 18:58:06 -0500899 Returns:
900 True if we want to include this path in the package
901 """
902 return not (ptype in ('dir',) or
903 path.startswith('/usr/lib/debug/') or
904 os.path.splitext(path)[1] == '.mo' or
905 ('/man/' in path or '/info/' in path))
906
907
908def ReadlinkRoot(path, root):
909 """Like os.readlink(), but relative to a |root|
910
911 Args:
912 path: The symlink to read
913 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500914
Mike Frysinger35247af2012-11-16 18:58:06 -0500915 Returns:
916 A fully resolved symlink path
917 """
918 while os.path.islink(root + path):
919 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
920 return path
921
922
923def _GetFilesForTarget(target, root='/'):
924 """Locate all the files to package for |target|
925
926 This does not cover ELF dependencies.
927
928 Args:
929 target: The toolchain target name
930 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500931
Mike Frysinger35247af2012-11-16 18:58:06 -0500932 Returns:
933 A tuple of a set of all packable paths, and a set of all paths which
934 are also native ELFs
935 """
936 paths = set()
937 elfs = set()
938
939 # Find all the files owned by the packages for this target.
940 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500941
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700942 # Skip Go compiler from redistributable packages.
943 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
944 # into it. Due to this, the toolchain cannot be unpacked anywhere
945 # else and be readily useful. To enable packaging Go, we need to:
946 # -) Tweak the wrappers/environment to override GOROOT
947 # automatically based on the unpack location.
948 # -) Make sure the ELF dependency checking and wrapping logic
949 # below skips the Go toolchain executables and libraries.
950 # -) Make sure the packaging process maintains the relative
951 # timestamps of precompiled standard library packages.
952 # (see dev-lang/go ebuild for details).
953 if pkg == 'ex_go':
954 continue
955
Yunlian Jiang36f35242018-04-27 10:18:40 -0700956 # Use armv7a-cros-linux-gnueabi/compiler-rt for
957 # armv7a-cros-linux-gnueabihf/compiler-rt.
958 # Currently the armv7a-cros-linux-gnueabi is actually
959 # the same as armv7a-cros-linux-gnueabihf with different names.
960 # Because of that, for compiler-rt, it generates the same binary in
961 # the same location. To avoid the installation conflict, we do not
962 # install anything for 'armv7a-cros-linux-gnueabihf'. This would cause
963 # problem if other people try to use standalone armv7a-cros-linux-gnueabihf
964 # toolchain.
965 if 'compiler-rt' in pkg and 'armv7a-cros-linux-gnueabi' in target:
966 atom = GetPortagePackage(target, pkg)
967 cat, pn = atom.split('/')
968 ver = GetInstalledPackageVersions(atom, root=root)[0]
Yunlian Jiang36f35242018-04-27 10:18:40 -0700969 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
970 settings=portage.settings)
971 contents = dblink.getcontents()
972 if not contents:
973 if 'hf' in target:
974 new_target = 'armv7a-cros-linux-gnueabi'
975 else:
976 new_target = 'armv7a-cros-linux-gnueabihf'
977 atom = GetPortagePackage(new_target, pkg)
978 else:
979 atom = GetPortagePackage(target, pkg)
980
Mike Frysinger35247af2012-11-16 18:58:06 -0500981 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700982 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700983 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500984
Mike Frysinger35247af2012-11-16 18:58:06 -0500985 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
986 settings=portage.settings)
987 contents = dblink.getcontents()
988 for obj in contents:
989 ptype = contents[obj][0]
990 if not IsPathPackagable(ptype, obj):
991 continue
992
993 if ptype == 'obj':
994 # For native ELFs, we need to pull in their dependencies too.
995 if FileIsCrosSdkElf(obj):
Mike Frysinger60a2f6c2019-12-04 04:18:58 -0500996 logging.debug('Adding ELF %s', obj)
Mike Frysinger35247af2012-11-16 18:58:06 -0500997 elfs.add(obj)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -0500998 logging.debug('Adding path %s', obj)
Mike Frysinger35247af2012-11-16 18:58:06 -0500999 paths.add(obj)
1000
1001 return paths, elfs
1002
1003
1004def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -05001005 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -05001006 """Link in all packable files and their runtime dependencies
1007
1008 This also wraps up executable ELFs with helper scripts.
1009
1010 Args:
1011 output_dir: The output directory to store files
1012 paths: All the files to include
1013 elfs: All the files which are ELFs (a subset of |paths|)
1014 ldpaths: A dict of static ldpath information
1015 path_rewrite_func: User callback to rewrite paths in output_dir
1016 root: The root path to pull all packages/files from
1017 """
1018 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -04001019 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -05001020 for path in paths:
1021 new_path = path_rewrite_func(path)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001022 logging.debug('Transformed %s to %s', path, new_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001023 dst = output_dir + new_path
1024 osutils.SafeMakedirs(os.path.dirname(dst))
1025
1026 # Is this a symlink which we have to rewrite or wrap?
1027 # Delay wrap check until after we have created all paths.
1028 src = root + path
1029 if os.path.islink(src):
1030 tgt = os.readlink(src)
1031 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -04001032 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -05001033
1034 # Rewrite absolute links to relative and then generate the symlink
1035 # ourselves. All other symlinks can be hardlinked below.
1036 if tgt[0] == '/':
1037 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
1038 os.symlink(tgt, dst)
1039 continue
1040
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001041 logging.debug('Linking path %s -> %s', src, dst)
Mike Frysinger35247af2012-11-16 18:58:06 -05001042 os.link(src, dst)
1043
Mike Frysinger35247af2012-11-16 18:58:06 -05001044 # Locate all the dependencies for all the ELFs. Stick them all in the
1045 # top level "lib" dir to make the wrapper simpler. This exact path does
1046 # not matter since we execute ldso directly, and we tell the ldso the
1047 # exact path to search for its libraries.
1048 libdir = os.path.join(output_dir, 'lib')
1049 osutils.SafeMakedirs(libdir)
1050 donelibs = set()
Mike Frysinger9fe02342019-12-12 17:52:53 -05001051 basenamelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -04001052 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -05001053 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -04001054 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001055 logging.debug('Parsed elf %s data: %s', elf, e)
Mike Frysinger35247af2012-11-16 18:58:06 -05001056 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -07001057 # Do not create wrapper for libc. crbug.com/766827
1058 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -05001059 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -04001060 interp = os.path.join('/lib', os.path.basename(interp))
1061 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
1062 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -07001063 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -05001064
Mike Frysinger221bd822017-09-29 02:51:47 -04001065 # Wrap any symlinks to the wrapper.
1066 if elf in sym_paths:
1067 link = sym_paths[elf]
1068 GeneratePathWrapper(output_dir, link, elf)
1069
Mike Frysinger9fe02342019-12-12 17:52:53 -05001070 # TODO(crbug.com/917193): Drop this hack once libopcodes linkage is fixed.
1071 if os.path.basename(elf).startswith('libopcodes-'):
1072 continue
Mike Frysinger35247af2012-11-16 18:58:06 -05001073
Mike Frysinger9fe02342019-12-12 17:52:53 -05001074 for lib, lib_data in e['libs'].items():
Mike Frysinger35247af2012-11-16 18:58:06 -05001075 src = path = lib_data['path']
1076 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001077 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001078 continue
Mike Frysinger9fe02342019-12-12 17:52:53 -05001079
1080 # No need to try and copy the same source lib multiple times.
1081 if path in donelibs:
1082 continue
1083 donelibs.add(path)
1084
1085 # Die if we try to normalize different source libs with the same basename.
1086 if lib in basenamelibs:
1087 logging.error('Multiple sources detected for %s:\n new: %s\n old: %s',
1088 os.path.join('/lib', lib), path,
1089 ' '.join(x for x in donelibs
1090 if x != path and os.path.basename(x) == lib))
1091 # TODO(crbug.com/917193): Make this fatal.
1092 # cros_build_lib.Die('Unable to resolve lib conflicts')
1093 continue
1094 basenamelibs.add(lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001095
1096 # Needed libs are the SONAME, but that is usually a symlink, not a
1097 # real file. So link in the target rather than the symlink itself.
1098 # We have to walk all the possible symlinks (SONAME could point to a
1099 # symlink which points to a symlink), and we have to handle absolute
1100 # ourselves (since we have a "root" argument).
1101 dst = os.path.join(libdir, os.path.basename(path))
1102 src = ReadlinkRoot(src, root)
1103
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001104 logging.debug('Linking lib %s -> %s', root + src, dst)
Mike Frysinger35247af2012-11-16 18:58:06 -05001105 os.link(root + src, dst)
1106
1107
1108def _EnvdGetVar(envd, var):
1109 """Given a Gentoo env.d file, extract a var from it
1110
1111 Args:
1112 envd: The env.d file to load (may be a glob path)
1113 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001114
Mike Frysinger35247af2012-11-16 18:58:06 -05001115 Returns:
1116 The value of |var|
1117 """
1118 envds = glob.glob(envd)
1119 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1120 envd = envds[0]
Mike Frysingere652ba12019-09-08 00:57:43 -04001121 return key_value_store.LoadFile(envd)[var]
Mike Frysinger35247af2012-11-16 18:58:06 -05001122
1123
1124def _ProcessBinutilsConfig(target, output_dir):
1125 """Do what binutils-config would have done"""
1126 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001127
1128 # Locate the bin dir holding the gold linker.
1129 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1130 target, 'binutils-bin')
1131 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001132 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001133 if not srcpath:
1134 # Maybe this target doesn't support gold.
1135 globpath = os.path.join(binutils_bin_path, '*')
1136 srcpath = glob.glob(globpath)
1137 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1138 % globpath)
1139 srcpath = srcpath[0]
1140 ld_path = os.path.join(srcpath, 'ld')
1141 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1142 ld_path = os.path.join(srcpath, 'ld.bfd')
1143 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1144 ld_path = os.path.join(srcpath, 'ld.gold')
1145 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1146 % ld_path)
1147
1148 # Nope, no gold support to be found.
1149 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001150 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001151 else:
1152 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001153 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001154
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001155 # Package the binutils-bin directory without the '-gold' suffix
1156 # if gold is not enabled as the default linker for this target.
1157 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1158 if not gold_supported:
1159 srcpath = srcpath[:-len('-gold')]
1160 ld_path = os.path.join(srcpath, 'ld')
1161 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1162
Mike Frysinger78b7a812014-11-26 19:45:23 -05001163 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001164 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1165 for prog in os.listdir(output_dir + srcpath):
1166 # Skip binaries already wrapped.
1167 if not prog.endswith('.real'):
1168 GeneratePathWrapper(output_dir, binpath + prog,
1169 os.path.join(srcpath, prog))
1170 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1171 os.path.join(srcpath, prog))
1172
David James27ac4ae2012-12-03 23:16:15 -08001173 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001174 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1175 if gold_supported:
1176 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001177 else:
1178 # If gold is not enabled as the default linker and 2 env.d
1179 # files exist, pick the one without the '-gold' suffix.
1180 envds = sorted(glob.glob(envd))
1181 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1182 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001183 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1184 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1185 output_dir + libpath)
1186
1187
1188def _ProcessGccConfig(target, output_dir):
1189 """Do what gcc-config would have done"""
1190 binpath = '/bin'
1191 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1192 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1193 for prog in os.listdir(output_dir + srcpath):
1194 # Skip binaries already wrapped.
1195 if (not prog.endswith('.real') and
1196 not prog.endswith('.elf') and
1197 prog.startswith(target)):
1198 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1199 os.path.join(srcpath, prog))
1200 return srcpath
1201
1202
Frank Henigman179ec7c2015-02-06 03:01:09 -05001203def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1204 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001205 # Disable ccache since we know it won't work outside of chroot.
Tobias Boschddd16492019-08-14 09:29:54 -07001206
Tobias Boschddd16492019-08-14 09:29:54 -07001207 # Use the version of the wrapper that does not use ccache.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001208 for sysroot_wrapper in glob.glob(os.path.join(
Tobias Boschddd16492019-08-14 09:29:54 -07001209 output_dir + srcpath, 'sysroot_wrapper*.ccache')):
1210 # Can't update the wrapper in place to not affect the chroot,
1211 # but only the extracted toolchain.
1212 os.unlink(sysroot_wrapper)
1213 shutil.copy(sysroot_wrapper[:-6] + 'noccache', sysroot_wrapper)
Tobias Bosch7bc907a2019-10-09 11:52:40 -07001214 shutil.copy(sysroot_wrapper[:-6] + 'noccache.elf', sysroot_wrapper + '.elf')
Mike Frysinger35247af2012-11-16 18:58:06 -05001215
1216
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001217def _CreateMainLibDir(target, output_dir):
1218 """Create some lib dirs so that compiler can get the right Gcc paths"""
1219 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1220 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1221
1222
Mike Frysinger35247af2012-11-16 18:58:06 -05001223def _ProcessDistroCleanups(target, output_dir):
1224 """Clean up the tree and remove all distro-specific requirements
1225
1226 Args:
1227 target: The toolchain target name
1228 output_dir: The output directory to clean up
1229 """
1230 _ProcessBinutilsConfig(target, output_dir)
1231 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001232 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001233 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001234
1235 osutils.RmDir(os.path.join(output_dir, 'etc'))
1236
1237
1238def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1239 """Setup a tree from the packages for the specified target
1240
1241 This populates a path with all the files from toolchain packages so that
1242 a tarball can easily be generated from the result.
1243
1244 Args:
1245 target: The target to create a packagable root from
1246 output_dir: The output directory to place all the files
1247 ldpaths: A dict of static ldpath information
1248 root: The root path to pull all packages/files from
1249 """
1250 # Find all the files owned by the packages for this target.
1251 paths, elfs = _GetFilesForTarget(target, root=root)
1252
1253 # Link in all the package's files, any ELF dependencies, and wrap any
1254 # executable ELFs with helper scripts.
1255 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001256 """Move /usr/bin to /bin so people can just use that toplevel dir
1257
George Burgess IVca1d7612020-10-01 00:38:32 -07001258 Note we do not apply this to clang or rust - there is correlation between
1259 clang's search path for libraries / inclusion and its installation path.
Han Shen699ea192016-03-02 10:42:47 -08001260 """
George Burgess IVca1d7612020-10-01 00:38:32 -07001261 if (path.startswith('/usr/bin/') and
1262 not any(x in path for x in ('clang', 'rust', 'cargo'))):
Han Shen699ea192016-03-02 10:42:47 -08001263 return path[4:]
1264 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001265 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1266 path_rewrite_func=MoveUsrBinToBin, root=root)
1267
1268 # The packages, when part of the normal distro, have helper scripts
1269 # that setup paths and such. Since we are making this standalone, we
1270 # need to preprocess all that ourselves.
1271 _ProcessDistroCleanups(target, output_dir)
1272
1273
1274def CreatePackages(targets_wanted, output_dir, root='/'):
1275 """Create redistributable cross-compiler packages for the specified targets
1276
1277 This creates toolchain packages that should be usable in conjunction with
1278 a downloaded sysroot (created elsewhere).
1279
1280 Tarballs (one per target) will be created in $PWD.
1281
1282 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001283 targets_wanted: The targets to package up.
1284 output_dir: The directory to put the packages in.
1285 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001286 """
Ralph Nathan03047282015-03-23 11:09:32 -07001287 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001288 osutils.SafeMakedirs(output_dir)
1289 ldpaths = lddtree.LoadLdpaths(root)
1290 targets = ExpandTargets(targets_wanted)
1291
Mike Frysinger221bd822017-09-29 02:51:47 -04001292 with osutils.TempDir(prefix='create-packages') as tempdir:
1293 logging.debug('Using tempdir: %s', tempdir)
1294
Mike Frysinger35247af2012-11-16 18:58:06 -05001295 # We have to split the root generation from the compression stages. This is
1296 # because we hardlink in all the files (to avoid overhead of reading/writing
1297 # the copies multiple times). But tar gets angry if a file's hardlink count
1298 # changes from when it starts reading a file to when it finishes.
1299 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1300 for target in targets:
1301 output_target_dir = os.path.join(tempdir, target)
1302 queue.put([target, output_target_dir, ldpaths, root])
1303
1304 # Build the tarball.
1305 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1306 for target in targets:
1307 tar_file = os.path.join(output_dir, target + '.tar.xz')
1308 queue.put([tar_file, os.path.join(tempdir, target)])
1309
1310
Mike Frysinger07534cf2017-09-12 17:40:21 -04001311def GetParser():
1312 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001313 parser = commandline.ArgumentParser(description=__doc__)
1314 parser.add_argument('-u', '--nousepkg',
1315 action='store_false', dest='usepkg', default=True,
1316 help='Use prebuilt packages if possible')
1317 parser.add_argument('-d', '--deleteold',
1318 action='store_true', dest='deleteold', default=False,
1319 help='Unmerge deprecated packages')
1320 parser.add_argument('-t', '--targets',
1321 dest='targets', default='sdk',
Mike Frysinger80de5012019-08-01 14:10:53 -04001322 help='Comma separated list of tuples. Special keywords '
Don Garrettc0c74002015-10-09 12:58:19 -07001323 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001324 "allowed. Defaults to 'sdk'.")
1325 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1326 help='Comma separated list of boards whose toolchains we '
1327 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001328 parser.add_argument('--hostonly',
1329 dest='hostonly', default=False, action='store_true',
1330 help='Only setup the host toolchain. '
1331 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001332 parser.add_argument('--show-board-cfg', '--show-cfg',
1333 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001334 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001335 parser.add_argument('--show-packages', default=None,
1336 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001337 parser.add_argument('--create-packages',
1338 action='store_true', default=False,
1339 help='Build redistributable packages')
1340 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1341 help='Output directory')
1342 parser.add_argument('--reconfig', default=False, action='store_true',
1343 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001344 parser.add_argument('--sysroot', type='path',
1345 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001346 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001347
Mike Frysinger07534cf2017-09-12 17:40:21 -04001348
1349def main(argv):
1350 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001351 options = parser.parse_args(argv)
1352 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001353
Mike Frysinger35247af2012-11-16 18:58:06 -05001354 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001355 conflicting_options = (
1356 options.cfg_name,
1357 options.show_packages,
1358 options.create_packages,
1359 )
1360 if sum(bool(x) for x in conflicting_options) > 1:
1361 parser.error('conflicting options: create-packages & show-packages & '
1362 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001363
Gilad Arnold8195b532015-04-07 10:56:30 +03001364 targets_wanted = set(options.targets.split(','))
1365 boards_wanted = (set(options.include_boards.split(','))
1366 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001367
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001368 if options.cfg_name:
1369 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001370 elif options.show_packages is not None:
1371 cros_build_lib.AssertInsideChroot()
1372 target = options.show_packages
1373 Crossdev.Load(False)
1374 for package in GetTargetPackages(target):
1375 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001376 elif options.create_packages:
1377 cros_build_lib.AssertInsideChroot()
1378 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001379 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001380 else:
1381 cros_build_lib.AssertInsideChroot()
1382 # This has to be always run as root.
1383 if os.geteuid() != 0:
1384 cros_build_lib.Die('this script must be run as root')
1385
1386 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001387 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001388 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001389 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001390 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001391 Crossdev.Save()
1392
1393 return 0