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