blob: 5f6fc616af60f30f7831152f061ebb8f552f183e [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Zdenek Behan508dcce2011-12-05 15:39:32 +01002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Mike Frysinger750c5f52014-09-16 16:16:57 -04006"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01007
Mike Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Mike Frysinger3ed47722017-08-08 14:59:08 -040010import errno
Mike Frysinger35247af2012-11-16 18:58:06 -050011import glob
Mike Frysinger3ed47722017-08-08 14:59:08 -040012import hashlib
Mike Frysinger7ccee992012-06-01 21:27:59 -040013import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010014import os
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -070015import re
Zdenek Behan508dcce2011-12-05 15:39:32 +010016
Aviv Keshetb7519e12016-10-04 00:50:00 -070017from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050018from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080019from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070020from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070021from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050022from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080023from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050024
25# Needs to be after chromite imports.
26import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010027
Mike Frysinger31596002012-12-03 23:54:24 -050028if cros_build_lib.IsInsideChroot():
29 # Only import portage after we've checked that we're inside the chroot.
30 # Outside may not have portage, in which case the above may not happen.
31 # We'll check in main() if the operation needs portage.
Mike Frysinger27e21b72018-07-12 14:20:21 -040032 # pylint: disable=import-error
Mike Frysinger31596002012-12-03 23:54:24 -050033 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010034
35
Matt Tennantf1e30972012-03-02 16:30:07 -080036EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010037PACKAGE_STABLE = '[stable]'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010038
39CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070040ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010041STABLE_OVERLAY = '/usr/local/portage/stable'
42CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010043
44
Mike Frysinger66bfde52017-09-12 16:42:57 -040045# The exact list of host toolchain packages we care about. These are the
46# packages that bots/devs install only from binpkgs and rely on the SDK bot
47# (chromiumos-sdk) to validate+uprev.
48#
Mike Frysinger66bfde52017-09-12 16:42:57 -040049# We don't use crossdev to manage the host toolchain for us, especially since
50# we diverge significantly now (with llvm/clang/etc...), and we don't need or
51# want crossdev managing /etc/portage config files for the sdk
52HOST_PACKAGES = (
53 'dev-lang/go',
Yunlian Jiang2cb91dc2018-03-08 10:56:27 -080054 'dev-libs/elfutils',
Mike Frysinger66bfde52017-09-12 16:42:57 -040055 'sys-devel/binutils',
56 'sys-devel/clang',
57 'sys-devel/gcc',
Yunlian Jiangf5721f32017-10-31 11:43:11 -070058 'sys-devel/lld',
Mike Frysinger66bfde52017-09-12 16:42:57 -040059 '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',
72 'dev-util/cargo',
Mike Frysinger61a24392017-10-17 17:14:27 -040073 'virtual/target-sdk-post-cross',
Patrick Georgi043ce6e2019-02-20 22:27:09 +010074 'dev-embedded/coreboot-sdk',
Mike Frysinger785b0c32017-09-13 01:35:59 -040075)
76
77# New packages that we're in the process of adding to the SDK. Since the SDK
78# bot hasn't had a chance to run yet, there are no binary packages available,
79# so we have to list them here and wait. Once it completes, entries here can
80# be removed so they'll end up on bots & dev's systems.
81NEW_PACKAGES = (
Mike Frysinger785b0c32017-09-13 01:35:59 -040082)
83
Rahul Chaudhry4b803052015-05-13 15:25:56 -070084# Enable the Go compiler for these targets.
85TARGET_GO_ENABLED = (
86 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070087 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070088 'armv7a-cros-linux-gnueabihf',
Rahul Chaudhry4d416582017-10-25 12:31:58 -070089 'aarch64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070090)
91CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
92
Manoj Gupta1b5642e2017-03-08 16:44:12 -080093# Enable llvm's compiler-rt for these targets.
94TARGET_COMPILER_RT_ENABLED = (
95 'armv7a-cros-linux-gnueabi',
Yunlian Jiang1b77ee42017-10-06 13:44:29 -070096 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070097 'aarch64-cros-linux-gnu',
Manoj Gupta21f3a082018-03-06 21:25:39 -080098 'armv7m-cros-eabi',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080099)
100CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
101
Manoj Gupta946abb42017-04-12 14:27:19 -0700102TARGET_LLVM_PKGS_ENABLED = (
103 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700104 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -0700105 'aarch64-cros-linux-gnu',
106 'x86_64-cros-linux-gnu',
107)
108
109LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -0700110 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
111 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700112 'ex_llvm-libunwind' : ['--ex-pkg', 'sys-libs/llvm-libunwind'],
Manoj Gupta946abb42017-04-12 14:27:19 -0700113}
114
Zdenek Behan508dcce2011-12-05 15:39:32 +0100115# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
116CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500117 'binutils' : {
Manoj Guptaa91e38e2018-11-15 11:07:48 -0800118 'aarch64-cros-linux-gnu' : '-gold',
Mike Frysinger8a83c622015-05-28 00:35:05 -0400119 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800120 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700121 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500122 'i686-pc-linux-gnu' : '-gold',
123 'x86_64-cros-linux-gnu' : '-gold',
124 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100125}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100126
127
David James66a09c42012-11-05 13:31:38 -0800128class Crossdev(object):
129 """Class for interacting with crossdev and caching its output."""
130
131 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
132 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800133 # Packages that needs separate handling, in addition to what we have from
134 # crossdev.
135 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700136 'clang': 'sys-devel',
Yunlian Jiang18ae9982017-11-03 09:15:31 -0700137 'lld': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800138 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700139 'libcxxabi': 'sys-libs',
140 'libcxx': 'sys-libs',
Yunlian Jiangda3ce5f2018-04-25 14:10:01 -0700141 'elfutils': 'dev-libs',
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700142 'llvm-libunwind': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800143 }
David James66a09c42012-11-05 13:31:38 -0800144
145 @classmethod
146 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400147 """Load crossdev cache from disk.
148
149 We invalidate the cache when crossdev updates or this script changes.
150 """
David James90239b92012-11-05 15:31:34 -0800151 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400152 # If we run the compiled/cached .pyc file, we'll read/hash that when we
153 # really always want to track the source .py file.
154 script = os.path.abspath(__file__)
155 if script.endswith('.pyc'):
156 script = script[:-1]
157 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
158
159 cls._CACHE = {
160 'crossdev_version': crossdev_version,
161 'setup_toolchains_hash': setup_toolchains_hash,
162 }
163
164 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
165 if reconfig:
166 logging.debug('cache: forcing regen due to reconfig')
167 return
168
169 try:
170 file_data = osutils.ReadFile(cls._CACHE_FILE)
171 except IOError as e:
172 if e.errno != errno.ENOENT:
173 logging.warning('cache: reading failed: %s', e)
174 osutils.SafeUnlink(cls._CACHE_FILE)
175 return
176
177 try:
178 data = json.loads(file_data)
179 except ValueError as e:
180 logging.warning('cache: ignoring invalid content: %s', e)
181 return
182
183 if crossdev_version != data.get('crossdev_version'):
184 logging.debug('cache: rebuilding after crossdev upgrade')
185 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
186 logging.debug('cache: rebuilding after cros_setup_toolchains change')
187 else:
188 logging.debug('cache: content is up-to-date!')
189 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800190
191 @classmethod
192 def Save(cls):
193 """Store crossdev cache on disk."""
194 # Save the cache from the successful run.
195 with open(cls._CACHE_FILE, 'w') as f:
196 json.dump(cls._CACHE, f)
197
198 @classmethod
199 def GetConfig(cls, target):
200 """Returns a map of crossdev provided variables about a tuple."""
201 CACHE_ATTR = '_target_tuple_map'
202
203 val = cls._CACHE.setdefault(CACHE_ATTR, {})
204 if not target in val:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400205 if target.startswith('host'):
Mike Frysinger66bfde52017-09-12 16:42:57 -0400206 conf = {
207 'crosspkgs': [],
208 'target': toolchain.GetHostTuple(),
209 }
Mike Frysinger785b0c32017-09-13 01:35:59 -0400210 if target == 'host':
211 packages_list = HOST_PACKAGES
212 else:
213 packages_list = HOST_POST_CROSS_PACKAGES
Mike Frysinger66bfde52017-09-12 16:42:57 -0400214 manual_pkgs = dict((pkg, cat) for cat, pkg in
Mike Frysinger785b0c32017-09-13 01:35:59 -0400215 [x.split('/') for x in packages_list])
Mike Frysinger66bfde52017-09-12 16:42:57 -0400216 else:
217 # Build the crossdev command.
218 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
219 if target in TARGET_COMPILER_RT_ENABLED:
220 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
221 if target in TARGET_GO_ENABLED:
222 cmd.extend(CROSSDEV_GO_ARGS)
223 if target in TARGET_LLVM_PKGS_ENABLED:
224 for pkg in LLVM_PKGS_TABLE:
225 cmd.extend(LLVM_PKGS_TABLE[pkg])
226 cmd.extend(['-t', target])
227 # Catch output of crossdev.
228 out = cros_build_lib.RunCommand(
229 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
230 # List of tuples split at the first '=', converted into dict.
231 conf = dict((k, cros_build_lib.ShellUnquote(v))
232 for k, v in (x.split('=', 1) for x in out))
233 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800234
Mike Frysinger66bfde52017-09-12 16:42:57 -0400235 manual_pkgs = cls.MANUAL_PKGS
236
237 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400238 conf[pkg + '_pn'] = pkg
239 conf[pkg + '_category'] = cat
240 if pkg not in conf['crosspkgs']:
241 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800242
243 val[target] = conf
244
David James66a09c42012-11-05 13:31:38 -0800245 return val[target]
246
247 @classmethod
248 def UpdateTargets(cls, targets, usepkg, config_only=False):
249 """Calls crossdev to initialize a cross target.
250
251 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700252 targets: The list of targets to initialize using crossdev.
253 usepkg: Copies the commandline opts.
254 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800255 """
256 configured_targets = cls._CACHE.setdefault('configured_targets', [])
257
258 cmdbase = ['crossdev', '--show-fail-log']
259 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
260 # Pick stable by default, and override as necessary.
261 cmdbase.extend(['-P', '--oneshot'])
262 if usepkg:
263 cmdbase.extend(['-P', '--getbinpkg',
264 '-P', '--usepkgonly',
265 '--without-headers'])
266
Christopher Wileyb22c0712015-06-02 10:37:03 -0700267 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800268 cmdbase.extend(['--overlays', overlays])
269 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
270
Yunlian Jiang4ff84172018-05-12 13:03:01 -0700271 # Build target by the reversed alphabetical order to make sure
272 # armv7a-cros-linux-gnueabihf builds before armv7a-cros-linux-gnueabi
Yunlian Jiang85c606a2017-10-10 20:58:53 -0700273 # because some dependency issue. This can be reverted once we
274 # migrated to armv7a-cros-linux-gnueabihf. crbug.com/711369
Yunlian Jiang4ff84172018-05-12 13:03:01 -0700275 for target in sorted(targets, reverse=True):
David James66a09c42012-11-05 13:31:38 -0800276 if config_only and target in configured_targets:
277 continue
278
279 cmd = cmdbase + ['-t', target]
280
281 for pkg in GetTargetPackages(target):
282 if pkg == 'gdb':
283 # Gdb does not have selectable versions.
284 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700285 elif pkg == 'ex_compiler-rt':
286 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700287 elif pkg == 'ex_go':
288 # Go does not have selectable versions.
289 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700290 elif pkg in LLVM_PKGS_TABLE:
291 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800292 elif pkg in cls.MANUAL_PKGS:
293 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700294 else:
295 # The first of the desired versions is the "primary" one.
296 version = GetDesiredPackageVersions(target, pkg)[0]
297 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800298
299 cmd.extend(targets[target]['crossdev'].split())
300 if config_only:
301 # In this case we want to just quietly reinit
302 cmd.append('--init-target')
303 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
304 else:
305 cros_build_lib.RunCommand(cmd)
306
307 configured_targets.append(target)
308
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100309
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100310def GetTargetPackages(target):
311 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800312 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100313 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800314 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100315
316
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100317# Portage helper functions:
318def GetPortagePackage(target, package):
319 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800320 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100321 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400322 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100323 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100324 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100325 category = conf['category']
326 # Portage package:
327 pn = conf[package + '_pn']
328 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500329 assert category
330 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100331 return '%s/%s' % (category, pn)
332
333
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700334def PortageTrees(root):
335 """Return the portage trees for a given root."""
336 if root == '/':
337 return portage.db['/']
338 # The portage logic requires the path always end in a slash.
339 root = root.rstrip('/') + '/'
340 return portage.create_trees(target_root=root, config_root=root)[root]
341
342
343def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100344 """Extracts the list of current versions of a target, package pair.
345
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500346 Args:
347 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700348 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100349
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500350 Returns:
351 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100352 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100353 versions = []
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700354 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100355 version = portage.versions.cpv_getversion(pkg)
356 versions.append(version)
357 return versions
358
359
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700360def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100361 """Extracts the current stable version for a given package.
362
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500363 Args:
364 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
365 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700366 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100367
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500368 Returns:
369 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100370 """
David James90239b92012-11-05 15:31:34 -0800371 pkgtype = 'vartree' if installed else 'porttree'
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700372 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800373 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100374
375
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700376def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100377 """Resolves keywords in a given version list for a particular package.
378
379 Resolving means replacing PACKAGE_STABLE with the actual number.
380
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500381 Args:
382 target: The target to operate on (e.g. i686-pc-linux-gnu)
383 package: The target/package to operate on (e.g. gcc)
384 versions: List of versions to resolve
385 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700386 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100387
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500388 Returns:
389 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100390 """
391 resolved = []
David James90239b92012-11-05 15:31:34 -0800392 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700393 if not installed:
394 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100395 for version in versions:
396 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700397 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400398 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100399 resolved.append(version)
400 return resolved
401
402
403def GetDesiredPackageVersions(target, package):
404 """Produces the list of desired versions for each target, package pair.
405
406 The first version in the list is implicitly treated as primary, ie.
407 the version that will be initialized by crossdev and selected.
408
409 If the version is PACKAGE_STABLE, it really means the current version which
410 is emerged by using the package atom with no particular version key.
411 Since crossdev unmasks all packages by default, this will actually
412 mean 'unstable' in most cases.
413
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500414 Args:
415 target: The target to operate on (e.g. i686-pc-linux-gnu)
416 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100417
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500418 Returns:
419 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100420 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400421 if package in GetTargetPackages(target):
422 return [PACKAGE_STABLE]
423 else:
424 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100425
426
427def TargetIsInitialized(target):
428 """Verifies if the given list of targets has been correctly initialized.
429
430 This determines whether we have to call crossdev while emerging
431 toolchain packages or can do it using emerge. Emerge is naturally
432 preferred, because all packages can be updated in a single pass.
433
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500434 Args:
435 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100436
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500437 Returns:
438 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100439 """
440 # Check if packages for the given target all have a proper version.
441 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100442 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800443 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100444 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400445 if not (GetStablePackageVersion(atom, True) and
446 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100447 return False
448 return True
449 except cros_build_lib.RunCommandError:
450 # Fails - The target has likely never been initialized before.
451 return False
452
453
454def RemovePackageMask(target):
455 """Removes a package.mask file for the given platform.
456
457 The pre-existing package.mask files can mess with the keywords.
458
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500459 Args:
460 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100461 """
462 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700463 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100464
465
Zdenek Behan508dcce2011-12-05 15:39:32 +0100466# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700467def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500468 """Rebuild libtool as needed
469
470 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
471 gcc, libtool will break. We can't use binary packages either as those will
472 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700473
474 Args:
475 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500476 """
477 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700478 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500479 for line in f:
480 # Look for a line like:
481 # sys_lib_search_path_spec="..."
482 # It'll be a list of paths and gcc will be one of them.
483 if line.startswith('sys_lib_search_path_spec='):
484 line = line.rstrip()
485 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400486 root_path = os.path.join(root, path.lstrip(os.path.sep))
487 logging.debug('Libtool: checking %s', root_path)
488 if not os.path.exists(root_path):
489 logging.info('Rebuilding libtool after gcc upgrade')
490 logging.info(' %s', line)
491 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500492 needs_update = True
493 break
494
495 if needs_update:
496 break
497
498 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700499 cmd = [EMERGE_CMD, '--oneshot']
500 if root != '/':
501 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
502 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500503 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400504 else:
505 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500506
507
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700508def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100509 """Determines which packages need update/unmerge and defers to portage.
510
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500511 Args:
512 targets: The list of targets to update
513 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700514 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100515 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100516 # For each target, we do two things. Figure out the list of updates,
517 # and figure out the appropriate keywords/masks. Crossdev will initialize
518 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400519 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800520 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100521 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400522 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100523 # Record the highest needed version for each target, for masking purposes.
524 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100525 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100526 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400527 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100528 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700529 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100530 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200531 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400532 if pkg in NEW_PACKAGES and usepkg:
533 # Skip this binary package (for now).
534 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100535 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400536 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100537
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400538 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100539 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400540 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800541 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542
Mike Frysinger3bba5032016-09-20 14:15:04 -0400543 logging.info('Updating packages:')
544 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100545
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100546 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100547 if usepkg:
548 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700549 if root != '/':
550 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100551
552 cmd.extend(packages)
553 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800554 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100555
556
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700557def CleanTargets(targets, root='/'):
558 """Unmerges old packages that are assumed unnecessary.
559
560 Args:
561 targets: The list of targets to clean up.
562 root: The install root in which we want packages cleaned up.
563 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564 unmergemap = {}
565 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400566 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100567 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400568 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100569 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700570 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100571 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700572 # NOTE: This refers to installed packages (vartree) rather than the
573 # Portage version (porttree and/or bintree) when determining the current
574 # version. While this isn't the most accurate thing to do, it is probably
575 # a good simple compromise, which should have the desired result of
576 # uninstalling everything but the latest installed version. In
577 # particular, using the bintree (--usebinpkg) requires a non-trivial
578 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200579 desired_num = VersionListToNumeric(target, package, desired, True)
580 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400581 logging.warning('Error detecting stable version for %s, '
582 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200583 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100584 unmergemap[pkg] = set(current).difference(desired_num)
585
586 # Cleaning doesn't care about consistency and rebuilding package.* files.
587 packages = []
588 for pkg, vers in unmergemap.iteritems():
589 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
590
591 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400592 logging.info('Cleaning packages:')
593 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100594 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700595 if root != '/':
596 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100597 cmd.extend(packages)
598 cros_build_lib.RunCommand(cmd)
599 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400600 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100601
602
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700603def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100604 """Runs gcc-config and binutils-config to select the desired.
605
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500606 Args:
607 targets: The targets to select
608 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700609 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100610 """
611 for package in ['gcc', 'binutils']:
612 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400613 # See if this package is part of this target.
614 if package not in GetTargetPackages(target):
615 logging.debug('%s: %s is not used', target, package)
616 continue
617
Zdenek Behan508dcce2011-12-05 15:39:32 +0100618 # Pick the first version in the numbered list as the selected one.
619 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700620 desired_num = VersionListToNumeric(target, package, desired, True,
621 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100622 desired = desired_num[0]
623 # *-config does not play revisions, strip them, keep just PV.
624 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
625
Mike Frysinger785b0c32017-09-13 01:35:59 -0400626 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100627 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800628 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100629
630 # And finally, attach target to it.
631 desired = '%s-%s' % (target, desired)
632
633 # Target specific hacks
634 if package in suffixes:
635 if target in suffixes[package]:
636 desired += suffixes[package][target]
637
David James7ec5efc2012-11-06 09:39:49 -0800638 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700639 if root != '/':
640 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800641 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500642 result = cros_build_lib.RunCommand(
643 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
644 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]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700650 cros_build_lib.RunCommand(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:
680 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
681 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(
David James27ac4ae2012-12-03 23:16:15 -0800753 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400754 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
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 """
850 with open(elf) as f:
851 data = f.read(20)
852 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
853 return (data[0:4] == '\x7fELF' and
854 data[4] == '\x02' and
855 data[5] == '\x01' and
856 data[18] == '\x3e')
857
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):
971 elfs.add(obj)
972 paths.add(obj)
973
974 return paths, elfs
975
976
977def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500978 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500979 """Link in all packable files and their runtime dependencies
980
981 This also wraps up executable ELFs with helper scripts.
982
983 Args:
984 output_dir: The output directory to store files
985 paths: All the files to include
986 elfs: All the files which are ELFs (a subset of |paths|)
987 ldpaths: A dict of static ldpath information
988 path_rewrite_func: User callback to rewrite paths in output_dir
989 root: The root path to pull all packages/files from
990 """
991 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400992 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500993 for path in paths:
994 new_path = path_rewrite_func(path)
995 dst = output_dir + new_path
996 osutils.SafeMakedirs(os.path.dirname(dst))
997
998 # Is this a symlink which we have to rewrite or wrap?
999 # Delay wrap check until after we have created all paths.
1000 src = root + path
1001 if os.path.islink(src):
1002 tgt = os.readlink(src)
1003 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -04001004 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -05001005
1006 # Rewrite absolute links to relative and then generate the symlink
1007 # ourselves. All other symlinks can be hardlinked below.
1008 if tgt[0] == '/':
1009 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
1010 os.symlink(tgt, dst)
1011 continue
1012
1013 os.link(src, dst)
1014
Mike Frysinger35247af2012-11-16 18:58:06 -05001015 # Locate all the dependencies for all the ELFs. Stick them all in the
1016 # top level "lib" dir to make the wrapper simpler. This exact path does
1017 # not matter since we execute ldso directly, and we tell the ldso the
1018 # exact path to search for its libraries.
1019 libdir = os.path.join(output_dir, 'lib')
1020 osutils.SafeMakedirs(libdir)
1021 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -04001022 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -05001023 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -04001024 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -05001025 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -07001026 # Do not create wrapper for libc. crbug.com/766827
1027 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -05001028 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -04001029 interp = os.path.join('/lib', os.path.basename(interp))
1030 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
1031 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -07001032 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -05001033
Mike Frysinger221bd822017-09-29 02:51:47 -04001034 # Wrap any symlinks to the wrapper.
1035 if elf in sym_paths:
1036 link = sym_paths[elf]
1037 GeneratePathWrapper(output_dir, link, elf)
1038
Mike Frysinger35247af2012-11-16 18:58:06 -05001039 for lib, lib_data in e['libs'].iteritems():
1040 if lib in donelibs:
1041 continue
1042
1043 src = path = lib_data['path']
1044 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001045 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001046 continue
1047 donelibs.add(lib)
1048
1049 # Needed libs are the SONAME, but that is usually a symlink, not a
1050 # real file. So link in the target rather than the symlink itself.
1051 # We have to walk all the possible symlinks (SONAME could point to a
1052 # symlink which points to a symlink), and we have to handle absolute
1053 # ourselves (since we have a "root" argument).
1054 dst = os.path.join(libdir, os.path.basename(path))
1055 src = ReadlinkRoot(src, root)
1056
1057 os.link(root + src, dst)
1058
1059
1060def _EnvdGetVar(envd, var):
1061 """Given a Gentoo env.d file, extract a var from it
1062
1063 Args:
1064 envd: The env.d file to load (may be a glob path)
1065 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001066
Mike Frysinger35247af2012-11-16 18:58:06 -05001067 Returns:
1068 The value of |var|
1069 """
1070 envds = glob.glob(envd)
1071 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1072 envd = envds[0]
1073 return cros_build_lib.LoadKeyValueFile(envd)[var]
1074
1075
1076def _ProcessBinutilsConfig(target, output_dir):
1077 """Do what binutils-config would have done"""
1078 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001079
1080 # Locate the bin dir holding the gold linker.
1081 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1082 target, 'binutils-bin')
1083 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001084 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001085 if not srcpath:
1086 # Maybe this target doesn't support gold.
1087 globpath = os.path.join(binutils_bin_path, '*')
1088 srcpath = glob.glob(globpath)
1089 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1090 % globpath)
1091 srcpath = srcpath[0]
1092 ld_path = os.path.join(srcpath, 'ld')
1093 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1094 ld_path = os.path.join(srcpath, 'ld.bfd')
1095 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1096 ld_path = os.path.join(srcpath, 'ld.gold')
1097 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1098 % ld_path)
1099
1100 # Nope, no gold support to be found.
1101 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001102 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001103 else:
1104 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001105 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001106
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001107 # Package the binutils-bin directory without the '-gold' suffix
1108 # if gold is not enabled as the default linker for this target.
1109 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1110 if not gold_supported:
1111 srcpath = srcpath[:-len('-gold')]
1112 ld_path = os.path.join(srcpath, 'ld')
1113 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1114
Mike Frysinger78b7a812014-11-26 19:45:23 -05001115 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001116 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1117 for prog in os.listdir(output_dir + srcpath):
1118 # Skip binaries already wrapped.
1119 if not prog.endswith('.real'):
1120 GeneratePathWrapper(output_dir, binpath + prog,
1121 os.path.join(srcpath, prog))
1122 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1123 os.path.join(srcpath, prog))
1124
David James27ac4ae2012-12-03 23:16:15 -08001125 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001126 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1127 if gold_supported:
1128 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001129 else:
1130 # If gold is not enabled as the default linker and 2 env.d
1131 # files exist, pick the one without the '-gold' suffix.
1132 envds = sorted(glob.glob(envd))
1133 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1134 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001135 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1136 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1137 output_dir + libpath)
1138
1139
1140def _ProcessGccConfig(target, output_dir):
1141 """Do what gcc-config would have done"""
1142 binpath = '/bin'
1143 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1144 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1145 for prog in os.listdir(output_dir + srcpath):
1146 # Skip binaries already wrapped.
1147 if (not prog.endswith('.real') and
1148 not prog.endswith('.elf') and
1149 prog.startswith(target)):
1150 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1151 os.path.join(srcpath, prog))
1152 return srcpath
1153
1154
Frank Henigman179ec7c2015-02-06 03:01:09 -05001155def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1156 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001157 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001158 for sysroot_wrapper in glob.glob(os.path.join(
1159 output_dir + srcpath, 'sysroot_wrapper*')):
1160 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
Douglas Andersoncc828a52017-10-13 13:07:25 -07001161
1162 # In order to optimize startup time in the chroot we run python a little
1163 # differently there. Put it back to the more portable way here.
Mike Frysingerdcad4e02018-08-03 16:20:02 -04001164 # See https://crbug.com/773138 for some details.
Douglas Andersoncc828a52017-10-13 13:07:25 -07001165 if contents[0] == '#!/usr/bin/python2 -S':
1166 contents[0] = '#!/usr/bin/env python2'
1167
Frank Henigman179ec7c2015-02-06 03:01:09 -05001168 for num in xrange(len(contents)):
1169 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001170 assert 'True' in contents[num]
1171 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001172 break
1173 # Can't update the wrapper in place since it's a hardlink to a file in /.
1174 os.unlink(sysroot_wrapper)
1175 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1176 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001177
1178
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001179def _CreateMainLibDir(target, output_dir):
1180 """Create some lib dirs so that compiler can get the right Gcc paths"""
1181 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1182 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1183
1184
Mike Frysinger35247af2012-11-16 18:58:06 -05001185def _ProcessDistroCleanups(target, output_dir):
1186 """Clean up the tree and remove all distro-specific requirements
1187
1188 Args:
1189 target: The toolchain target name
1190 output_dir: The output directory to clean up
1191 """
1192 _ProcessBinutilsConfig(target, output_dir)
1193 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001194 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001195 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001196
1197 osutils.RmDir(os.path.join(output_dir, 'etc'))
1198
1199
1200def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1201 """Setup a tree from the packages for the specified target
1202
1203 This populates a path with all the files from toolchain packages so that
1204 a tarball can easily be generated from the result.
1205
1206 Args:
1207 target: The target to create a packagable root from
1208 output_dir: The output directory to place all the files
1209 ldpaths: A dict of static ldpath information
1210 root: The root path to pull all packages/files from
1211 """
1212 # Find all the files owned by the packages for this target.
1213 paths, elfs = _GetFilesForTarget(target, root=root)
1214
1215 # Link in all the package's files, any ELF dependencies, and wrap any
1216 # executable ELFs with helper scripts.
1217 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001218 """Move /usr/bin to /bin so people can just use that toplevel dir
1219
1220 Note we do not apply this to clang - there is correlation between clang's
1221 search path for libraries / inclusion and its installation path.
1222 """
1223 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1224 return path[4:]
1225 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001226 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1227 path_rewrite_func=MoveUsrBinToBin, root=root)
1228
1229 # The packages, when part of the normal distro, have helper scripts
1230 # that setup paths and such. Since we are making this standalone, we
1231 # need to preprocess all that ourselves.
1232 _ProcessDistroCleanups(target, output_dir)
1233
1234
1235def CreatePackages(targets_wanted, output_dir, root='/'):
1236 """Create redistributable cross-compiler packages for the specified targets
1237
1238 This creates toolchain packages that should be usable in conjunction with
1239 a downloaded sysroot (created elsewhere).
1240
1241 Tarballs (one per target) will be created in $PWD.
1242
1243 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001244 targets_wanted: The targets to package up.
1245 output_dir: The directory to put the packages in.
1246 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001247 """
Ralph Nathan03047282015-03-23 11:09:32 -07001248 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001249 osutils.SafeMakedirs(output_dir)
1250 ldpaths = lddtree.LoadLdpaths(root)
1251 targets = ExpandTargets(targets_wanted)
1252
Mike Frysinger221bd822017-09-29 02:51:47 -04001253 with osutils.TempDir(prefix='create-packages') as tempdir:
1254 logging.debug('Using tempdir: %s', tempdir)
1255
Mike Frysinger35247af2012-11-16 18:58:06 -05001256 # We have to split the root generation from the compression stages. This is
1257 # because we hardlink in all the files (to avoid overhead of reading/writing
1258 # the copies multiple times). But tar gets angry if a file's hardlink count
1259 # changes from when it starts reading a file to when it finishes.
1260 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1261 for target in targets:
1262 output_target_dir = os.path.join(tempdir, target)
1263 queue.put([target, output_target_dir, ldpaths, root])
1264
1265 # Build the tarball.
1266 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1267 for target in targets:
1268 tar_file = os.path.join(output_dir, target + '.tar.xz')
1269 queue.put([tar_file, os.path.join(tempdir, target)])
1270
1271
Mike Frysinger07534cf2017-09-12 17:40:21 -04001272def GetParser():
1273 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001274 parser = commandline.ArgumentParser(description=__doc__)
1275 parser.add_argument('-u', '--nousepkg',
1276 action='store_false', dest='usepkg', default=True,
1277 help='Use prebuilt packages if possible')
1278 parser.add_argument('-d', '--deleteold',
1279 action='store_true', dest='deleteold', default=False,
1280 help='Unmerge deprecated packages')
1281 parser.add_argument('-t', '--targets',
1282 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001283 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001284 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001285 "allowed. Defaults to 'sdk'.")
1286 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1287 help='Comma separated list of boards whose toolchains we '
1288 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001289 parser.add_argument('--hostonly',
1290 dest='hostonly', default=False, action='store_true',
1291 help='Only setup the host toolchain. '
1292 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001293 parser.add_argument('--show-board-cfg', '--show-cfg',
1294 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001295 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001296 parser.add_argument('--show-packages', default=None,
1297 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001298 parser.add_argument('--create-packages',
1299 action='store_true', default=False,
1300 help='Build redistributable packages')
1301 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1302 help='Output directory')
1303 parser.add_argument('--reconfig', default=False, action='store_true',
1304 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001305 parser.add_argument('--sysroot', type='path',
1306 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001307 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001308
Mike Frysinger07534cf2017-09-12 17:40:21 -04001309
1310def main(argv):
1311 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001312 options = parser.parse_args(argv)
1313 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001314
Mike Frysinger35247af2012-11-16 18:58:06 -05001315 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001316 conflicting_options = (
1317 options.cfg_name,
1318 options.show_packages,
1319 options.create_packages,
1320 )
1321 if sum(bool(x) for x in conflicting_options) > 1:
1322 parser.error('conflicting options: create-packages & show-packages & '
1323 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001324
Gilad Arnold8195b532015-04-07 10:56:30 +03001325 targets_wanted = set(options.targets.split(','))
1326 boards_wanted = (set(options.include_boards.split(','))
1327 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001328
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001329 if options.cfg_name:
1330 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001331 elif options.show_packages is not None:
1332 cros_build_lib.AssertInsideChroot()
1333 target = options.show_packages
1334 Crossdev.Load(False)
1335 for package in GetTargetPackages(target):
1336 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001337 elif options.create_packages:
1338 cros_build_lib.AssertInsideChroot()
1339 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001340 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001341 else:
1342 cros_build_lib.AssertInsideChroot()
1343 # This has to be always run as root.
1344 if os.geteuid() != 0:
1345 cros_build_lib.Die('this script must be run as root')
1346
1347 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001348 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001349 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001350 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001351 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001352 Crossdev.Save()
1353
1354 return 0