blob: 55be80971ad1b07c320ba4949f247def2d6bbad1 [file] [log] [blame]
Zdenek Behan508dcce2011-12-05 15:39:32 +01001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Mike Frysinger750c5f52014-09-16 16:16:57 -04005"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01006
Mike Frysinger383367e2014-09-16 15:06:17 -04007from __future__ import print_function
8
Zdenek Behan508dcce2011-12-05 15:39:32 +01009import copy
Mike Frysinger35247af2012-11-16 18:58:06 -050010import glob
Mike Frysinger7ccee992012-06-01 21:27:59 -040011import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010012import os
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -070013import re
Zdenek Behan508dcce2011-12-05 15:39:32 +010014
Aviv Keshetb7519e12016-10-04 00:50:00 -070015from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050016from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080017from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070018from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070019from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050020from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080021from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050022
23# Needs to be after chromite imports.
24import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010025
Mike Frysinger31596002012-12-03 23:54:24 -050026if cros_build_lib.IsInsideChroot():
27 # Only import portage after we've checked that we're inside the chroot.
28 # Outside may not have portage, in which case the above may not happen.
29 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070030 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050031 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010032
33
Matt Tennantf1e30972012-03-02 16:30:07 -080034EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010035PACKAGE_STABLE = '[stable]'
36PACKAGE_NONE = '[none]'
37SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
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
45# TODO: The versions are stored here very much like in setup_board.
46# The goal for future is to differentiate these using a config file.
47# This is done essentially by messing with GetDesiredPackageVersions()
48DEFAULT_VERSION = PACKAGE_STABLE
49DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010050}
51TARGET_VERSION_MAP = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050052 'host' : {
53 'gdb' : PACKAGE_NONE,
54 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010055}
Rahul Chaudhry4b803052015-05-13 15:25:56 -070056
57# Enable the Go compiler for these targets.
58TARGET_GO_ENABLED = (
59 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070060 'armv7a-cros-linux-gnueabi',
61)
62CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
63
Manoj Gupta1b5642e2017-03-08 16:44:12 -080064# Enable llvm's compiler-rt for these targets.
65TARGET_COMPILER_RT_ENABLED = (
66 'armv7a-cros-linux-gnueabi',
Manoj Gupta946abb42017-04-12 14:27:19 -070067 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080068)
69CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
70
Manoj Gupta946abb42017-04-12 14:27:19 -070071TARGET_LLVM_PKGS_ENABLED = (
72 'armv7a-cros-linux-gnueabi',
73 'aarch64-cros-linux-gnu',
74 'x86_64-cros-linux-gnu',
75)
76
77LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070078 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
79 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -070080}
81
Zdenek Behan508dcce2011-12-05 15:39:32 +010082# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
83CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050084 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040085 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080086 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050087 'i686-pc-linux-gnu' : '-gold',
88 'x86_64-cros-linux-gnu' : '-gold',
89 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010090}
Zdenek Behan508dcce2011-12-05 15:39:32 +010091# Global per-run cache that will be filled ondemand in by GetPackageMap()
92# function as needed.
93target_version_map = {
94}
95
96
David James66a09c42012-11-05 13:31:38 -080097class Crossdev(object):
98 """Class for interacting with crossdev and caching its output."""
99
100 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
101 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800102 # Packages that needs separate handling, in addition to what we have from
103 # crossdev.
104 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700105 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800106 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700107 'libcxxabi': 'sys-libs',
108 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800109 }
David James66a09c42012-11-05 13:31:38 -0800110
111 @classmethod
112 def Load(cls, reconfig):
113 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -0800114 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
115 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -0800116 if os.path.exists(cls._CACHE_FILE) and not reconfig:
117 with open(cls._CACHE_FILE) as f:
118 data = json.load(f)
David James90239b92012-11-05 15:31:34 -0800119 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -0800120 cls._CACHE = data
121
122 @classmethod
123 def Save(cls):
124 """Store crossdev cache on disk."""
125 # Save the cache from the successful run.
126 with open(cls._CACHE_FILE, 'w') as f:
127 json.dump(cls._CACHE, f)
128
129 @classmethod
130 def GetConfig(cls, target):
131 """Returns a map of crossdev provided variables about a tuple."""
132 CACHE_ATTR = '_target_tuple_map'
133
134 val = cls._CACHE.setdefault(CACHE_ATTR, {})
135 if not target in val:
136 # Find out the crossdev tuple.
137 target_tuple = target
138 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800139 target_tuple = toolchain.GetHostTuple()
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700140 # Build the crossdev command.
141 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
Manoj Gupta1b5642e2017-03-08 16:44:12 -0800142 if target in TARGET_COMPILER_RT_ENABLED:
143 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Manoj Guptab8181562017-05-21 10:18:59 -0700144 if target in TARGET_GO_ENABLED:
145 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700146 if target in TARGET_LLVM_PKGS_ENABLED:
147 for pkg in LLVM_PKGS_TABLE:
148 cmd.extend(LLVM_PKGS_TABLE[pkg])
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700149 cmd.extend(['-t', target_tuple])
David James66a09c42012-11-05 13:31:38 -0800150 # Catch output of crossdev.
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700151 out = cros_build_lib.RunCommand(cmd, print_cmd=False,
152 redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800153 # List of tuples split at the first '=', converted into dict.
Han Shene23782f2016-02-18 12:20:00 -0800154 conf = dict((k, cros_build_lib.ShellUnquote(v))
155 for k, v in (x.split('=', 1) for x in out))
156 conf['crosspkgs'] = conf['crosspkgs'].split()
157
158 for pkg, cat in cls.MANUAL_PKGS.iteritems():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400159 conf[pkg + '_pn'] = pkg
160 conf[pkg + '_category'] = cat
161 if pkg not in conf['crosspkgs']:
162 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800163
164 val[target] = conf
165
David James66a09c42012-11-05 13:31:38 -0800166 return val[target]
167
168 @classmethod
169 def UpdateTargets(cls, targets, usepkg, config_only=False):
170 """Calls crossdev to initialize a cross target.
171
172 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700173 targets: The list of targets to initialize using crossdev.
174 usepkg: Copies the commandline opts.
175 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800176 """
177 configured_targets = cls._CACHE.setdefault('configured_targets', [])
178
179 cmdbase = ['crossdev', '--show-fail-log']
180 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
181 # Pick stable by default, and override as necessary.
182 cmdbase.extend(['-P', '--oneshot'])
183 if usepkg:
184 cmdbase.extend(['-P', '--getbinpkg',
185 '-P', '--usepkgonly',
186 '--without-headers'])
187
Christopher Wileyb22c0712015-06-02 10:37:03 -0700188 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800189 cmdbase.extend(['--overlays', overlays])
190 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
191
192 for target in targets:
193 if config_only and target in configured_targets:
194 continue
195
196 cmd = cmdbase + ['-t', target]
197
198 for pkg in GetTargetPackages(target):
199 if pkg == 'gdb':
200 # Gdb does not have selectable versions.
201 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700202 elif pkg == 'ex_compiler-rt':
203 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700204 elif pkg == 'ex_go':
205 # Go does not have selectable versions.
206 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700207 elif pkg in LLVM_PKGS_TABLE:
208 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800209 elif pkg in cls.MANUAL_PKGS:
210 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700211 else:
212 # The first of the desired versions is the "primary" one.
213 version = GetDesiredPackageVersions(target, pkg)[0]
214 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800215
216 cmd.extend(targets[target]['crossdev'].split())
217 if config_only:
218 # In this case we want to just quietly reinit
219 cmd.append('--init-target')
220 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
221 else:
222 cros_build_lib.RunCommand(cmd)
223
224 configured_targets.append(target)
225
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100226
Zdenek Behan508dcce2011-12-05 15:39:32 +0100227def GetPackageMap(target):
228 """Compiles a package map for the given target from the constants.
229
230 Uses a cache in target_version_map, that is dynamically filled in as needed,
231 since here everything is static data and the structuring is for ease of
232 configurability only.
233
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500234 Args:
235 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100236
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500237 Returns:
238 A map between packages and desired versions in internal format
239 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100240 """
241 if target in target_version_map:
242 return target_version_map[target]
243
244 # Start from copy of the global defaults.
245 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
246
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100247 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100248 # prefer any specific overrides
249 if pkg in TARGET_VERSION_MAP.get(target, {}):
250 result[pkg] = TARGET_VERSION_MAP[target][pkg]
251 else:
252 # finally, if not already set, set a sane default
253 result.setdefault(pkg, DEFAULT_VERSION)
254 target_version_map[target] = result
255 return result
256
257
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100258def GetTargetPackages(target):
259 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800260 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100261 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800262 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100263
264
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100265# Portage helper functions:
266def GetPortagePackage(target, package):
267 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800268 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100269 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800270 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100271 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100272 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100273 category = conf['category']
274 # Portage package:
275 pn = conf[package + '_pn']
276 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500277 assert category
278 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100279 return '%s/%s' % (category, pn)
280
281
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100282def IsPackageDisabled(target, package):
283 """Returns if the given package is not used for the target."""
284 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
285
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100286
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700287def PortageTrees(root):
288 """Return the portage trees for a given root."""
289 if root == '/':
290 return portage.db['/']
291 # The portage logic requires the path always end in a slash.
292 root = root.rstrip('/') + '/'
293 return portage.create_trees(target_root=root, config_root=root)[root]
294
295
296def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100297 """Extracts the list of current versions of a target, package pair.
298
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500299 Args:
300 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700301 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100302
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500303 Returns:
304 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100305 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100306 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500307 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700308 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100309 version = portage.versions.cpv_getversion(pkg)
310 versions.append(version)
311 return versions
312
313
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700314def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100315 """Extracts the current stable version for a given package.
316
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500317 Args:
318 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
319 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700320 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100321
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500322 Returns:
323 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100324 """
David James90239b92012-11-05 15:31:34 -0800325 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500326 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700327 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800328 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100329
330
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700331def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100332 """Resolves keywords in a given version list for a particular package.
333
334 Resolving means replacing PACKAGE_STABLE with the actual number.
335
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500336 Args:
337 target: The target to operate on (e.g. i686-pc-linux-gnu)
338 package: The target/package to operate on (e.g. gcc)
339 versions: List of versions to resolve
340 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700341 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100342
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500343 Returns:
344 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100345 """
346 resolved = []
David James90239b92012-11-05 15:31:34 -0800347 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700348 if not installed:
349 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100350 for version in versions:
351 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700352 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100353 elif version != PACKAGE_NONE:
354 resolved.append(version)
355 return resolved
356
357
358def GetDesiredPackageVersions(target, package):
359 """Produces the list of desired versions for each target, package pair.
360
361 The first version in the list is implicitly treated as primary, ie.
362 the version that will be initialized by crossdev and selected.
363
364 If the version is PACKAGE_STABLE, it really means the current version which
365 is emerged by using the package atom with no particular version key.
366 Since crossdev unmasks all packages by default, this will actually
367 mean 'unstable' in most cases.
368
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500369 Args:
370 target: The target to operate on (e.g. i686-pc-linux-gnu)
371 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100372
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500373 Returns:
374 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100375 """
376 packagemap = GetPackageMap(target)
377
378 versions = []
379 if package in packagemap:
380 versions.append(packagemap[package])
381
382 return versions
383
384
385def TargetIsInitialized(target):
386 """Verifies if the given list of targets has been correctly initialized.
387
388 This determines whether we have to call crossdev while emerging
389 toolchain packages or can do it using emerge. Emerge is naturally
390 preferred, because all packages can be updated in a single pass.
391
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500392 Args:
393 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500395 Returns:
396 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100397 """
398 # Check if packages for the given target all have a proper version.
399 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100400 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800401 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100402 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800403 if not IsPackageDisabled(target, package) and not (
404 GetStablePackageVersion(atom, True) and
405 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100406 return False
407 return True
408 except cros_build_lib.RunCommandError:
409 # Fails - The target has likely never been initialized before.
410 return False
411
412
413def RemovePackageMask(target):
414 """Removes a package.mask file for the given platform.
415
416 The pre-existing package.mask files can mess with the keywords.
417
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500418 Args:
419 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100420 """
421 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700422 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100423
424
Zdenek Behan508dcce2011-12-05 15:39:32 +0100425# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700426def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500427 """Rebuild libtool as needed
428
429 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
430 gcc, libtool will break. We can't use binary packages either as those will
431 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700432
433 Args:
434 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500435 """
436 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700437 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500438 for line in f:
439 # Look for a line like:
440 # sys_lib_search_path_spec="..."
441 # It'll be a list of paths and gcc will be one of them.
442 if line.startswith('sys_lib_search_path_spec='):
443 line = line.rstrip()
444 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400445 root_path = os.path.join(root, path.lstrip(os.path.sep))
446 logging.debug('Libtool: checking %s', root_path)
447 if not os.path.exists(root_path):
448 logging.info('Rebuilding libtool after gcc upgrade')
449 logging.info(' %s', line)
450 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500451 needs_update = True
452 break
453
454 if needs_update:
455 break
456
457 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700458 cmd = [EMERGE_CMD, '--oneshot']
459 if root != '/':
460 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
461 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500462 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400463 else:
464 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500465
466
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700467def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100468 """Determines which packages need update/unmerge and defers to portage.
469
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500470 Args:
471 targets: The list of targets to update
472 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700473 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100474 """
David James90239b92012-11-05 15:31:34 -0800475 # Remove keyword files created by old versions of cros_setup_toolchains.
476 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100477
478 # For each target, we do two things. Figure out the list of updates,
479 # and figure out the appropriate keywords/masks. Crossdev will initialize
480 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400481 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800482 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100483 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400484 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100485 # Record the highest needed version for each target, for masking purposes.
486 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100487 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100488 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100489 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400490 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100491 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400492 logging.debug(' Updating package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100493 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700494 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100495 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200496 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100497 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100498
Zdenek Behan508dcce2011-12-05 15:39:32 +0100499 packages = []
500 for pkg in mergemap:
501 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200502 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800503 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100504
505 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400506 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800507 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100508
Mike Frysinger3bba5032016-09-20 14:15:04 -0400509 logging.info('Updating packages:')
510 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100511
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100512 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100513 if usepkg:
514 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700515 if root != '/':
516 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100517
518 cmd.extend(packages)
519 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800520 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100521
522
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700523def CleanTargets(targets, root='/'):
524 """Unmerges old packages that are assumed unnecessary.
525
526 Args:
527 targets: The list of targets to clean up.
528 root: The install root in which we want packages cleaned up.
529 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100530 unmergemap = {}
531 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400532 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100533 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100534 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400535 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100536 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400537 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100538 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700539 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100540 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700541 # NOTE: This refers to installed packages (vartree) rather than the
542 # Portage version (porttree and/or bintree) when determining the current
543 # version. While this isn't the most accurate thing to do, it is probably
544 # a good simple compromise, which should have the desired result of
545 # uninstalling everything but the latest installed version. In
546 # particular, using the bintree (--usebinpkg) requires a non-trivial
547 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200548 desired_num = VersionListToNumeric(target, package, desired, True)
549 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400550 logging.warning('Error detecting stable version for %s, '
551 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200552 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100553 unmergemap[pkg] = set(current).difference(desired_num)
554
555 # Cleaning doesn't care about consistency and rebuilding package.* files.
556 packages = []
557 for pkg, vers in unmergemap.iteritems():
558 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
559
560 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400561 logging.info('Cleaning packages:')
562 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100563 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700564 if root != '/':
565 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100566 cmd.extend(packages)
567 cros_build_lib.RunCommand(cmd)
568 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400569 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100570
571
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700572def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100573 """Runs gcc-config and binutils-config to select the desired.
574
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500575 Args:
576 targets: The targets to select
577 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700578 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100579 """
580 for package in ['gcc', 'binutils']:
581 for target in targets:
582 # Pick the first version in the numbered list as the selected one.
583 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700584 desired_num = VersionListToNumeric(target, package, desired, True,
585 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100586 desired = desired_num[0]
587 # *-config does not play revisions, strip them, keep just PV.
588 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
589
590 if target == 'host':
591 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800592 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100593
594 # And finally, attach target to it.
595 desired = '%s-%s' % (target, desired)
596
597 # Target specific hacks
598 if package in suffixes:
599 if target in suffixes[package]:
600 desired += suffixes[package][target]
601
David James7ec5efc2012-11-06 09:39:49 -0800602 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700603 if root != '/':
604 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800605 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500606 result = cros_build_lib.RunCommand(
607 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
608 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700609
610 # Do not reconfig when the current is live or nothing needs to be done.
611 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100612 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500613 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700614 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100615
616
Mike Frysinger35247af2012-11-16 18:58:06 -0500617def ExpandTargets(targets_wanted):
618 """Expand any possible toolchain aliases into full targets
619
620 This will expand 'all' and 'sdk' into the respective toolchain tuples.
621
622 Args:
623 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500624
Mike Frysinger35247af2012-11-16 18:58:06 -0500625 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300626 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500627 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500628 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700629 if targets_wanted == set(['boards']):
630 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300631 return {}
632
633 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500634 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300635 return all_targets
636 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500637 # Filter out all the non-sdk toolchains as we don't want to mess
638 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300639 return toolchain.FilterToolchains(all_targets, 'sdk', True)
640
641 # Verify user input.
642 nonexistent = targets_wanted.difference(all_targets)
643 if nonexistent:
644 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
645 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500646
647
David Jamesf8c672f2012-11-06 13:38:11 -0800648def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700649 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100650 """Performs all steps to create a synchronized toolchain enviroment.
651
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500652 Args:
653 usepkg: Use prebuilt packages
654 deleteold: Unmerge deprecated packages
655 hostonly: Only setup the host toolchain
656 reconfig: Reload crossdev config and reselect toolchains
657 targets_wanted: All the targets to update
658 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700659 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100660 """
David Jamesf8c672f2012-11-06 13:38:11 -0800661 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100662 if not hostonly:
663 # For hostonly, we can skip most of the below logic, much of which won't
664 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500665 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400666
Don Garrettc0c74002015-10-09 12:58:19 -0700667 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300668 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400669 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800670 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100671
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100672 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400673 for target in targets:
674 if TargetIsInitialized(target):
675 reconfig_targets[target] = targets[target]
676 else:
677 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100678 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400679 logging.info('The following targets need to be re-initialized:')
680 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800681 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200682 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800683 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100684
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100685 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400686 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100687
688 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700689 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
690 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800691
692 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700693 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100694
Mike Frysingerc880a962013-11-08 13:59:06 -0500695 # Now that we've cleared out old versions, see if we need to rebuild
696 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700697 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500698
Zdenek Behan508dcce2011-12-05 15:39:32 +0100699
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700700def ShowConfig(name):
701 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500702
703 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700704 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500705 """
Don Garrettc0c74002015-10-09 12:58:19 -0700706 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500707 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400708 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400709 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800710 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400711 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500712
713
Mike Frysinger35247af2012-11-16 18:58:06 -0500714def GeneratePathWrapper(root, wrappath, path):
715 """Generate a shell script to execute another shell script
716
717 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
718 argv[0] won't be pointing to the correct path, generate a shell script that
719 just executes another program with its full path.
720
721 Args:
722 root: The root tree to generate scripts inside of
723 wrappath: The full path (inside |root|) to create the wrapper
724 path: The target program which this wrapper will execute
725 """
726 replacements = {
727 'path': path,
728 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
729 }
730 wrapper = """#!/bin/sh
731base=$(realpath "$0")
732basedir=${base%%/*}
733exec "${basedir}/%(relroot)s%(path)s" "$@"
734""" % replacements
735 root_wrapper = root + wrappath
736 if os.path.islink(root_wrapper):
737 os.unlink(root_wrapper)
738 else:
739 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
740 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400741 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500742
743
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700744def FixClangXXWrapper(root, path):
745 """Fix wrapper shell scripts and symlinks for invoking clang++
746
747 In a typical installation, clang++ symlinks to clang, which symlinks to the
748 elf executable. The executable distinguishes between clang and clang++ based
749 on argv[0].
750
751 When invoked through the LdsoWrapper, argv[0] always contains the path to the
752 executable elf file, making clang/clang++ invocations indistinguishable.
753
754 This function detects if the elf executable being wrapped is clang-X.Y, and
755 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
756
757 The calling sequence now becomes:
758 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
759 the Ldsowrapper).
760 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
761 to the original clang-3.9 elf.
762 -) The difference this time is that inside the elf file execution, $0 is
763 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
764
765 Args:
766 root: The root tree to generate scripts / symlinks inside of
767 path: The target elf for which LdsoWrapper was created
768 """
769 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
770 logging.info('fixing clang++ invocation for %s', path)
771 clangdir = os.path.dirname(root + path)
772 clang = os.path.basename(path)
773 clangxx = clang.replace('clang', 'clang++')
774
775 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
776 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
777
778 # Create a hardlink clang++-X.Y pointing to clang-X.Y
779 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
780
781 # Adjust the clang++ symlink to point to clang++-X.Y
782 os.unlink(os.path.join(clangdir, 'clang++'))
783 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
784
785
Mike Frysinger35247af2012-11-16 18:58:06 -0500786def FileIsCrosSdkElf(elf):
787 """Determine if |elf| is an ELF that we execute in the cros_sdk
788
789 We don't need this to be perfect, just quick. It makes sure the ELF
790 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
791
792 Args:
793 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500794
Mike Frysinger35247af2012-11-16 18:58:06 -0500795 Returns:
796 True if we think |elf| is a native ELF
797 """
798 with open(elf) as f:
799 data = f.read(20)
800 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
801 return (data[0:4] == '\x7fELF' and
802 data[4] == '\x02' and
803 data[5] == '\x01' and
804 data[18] == '\x3e')
805
806
807def IsPathPackagable(ptype, path):
808 """Should the specified file be included in a toolchain package?
809
810 We only need to handle files as we'll create dirs as we need them.
811
812 Further, trim files that won't be useful:
813 - non-english translations (.mo) since it'd require env vars
814 - debug files since these are for the host compiler itself
815 - info/man pages as they're big, and docs are online, and the
816 native docs should work fine for the most part (`man gcc`)
817
818 Args:
819 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
820 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500821
Mike Frysinger35247af2012-11-16 18:58:06 -0500822 Returns:
823 True if we want to include this path in the package
824 """
825 return not (ptype in ('dir',) or
826 path.startswith('/usr/lib/debug/') or
827 os.path.splitext(path)[1] == '.mo' or
828 ('/man/' in path or '/info/' in path))
829
830
831def ReadlinkRoot(path, root):
832 """Like os.readlink(), but relative to a |root|
833
834 Args:
835 path: The symlink to read
836 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500837
Mike Frysinger35247af2012-11-16 18:58:06 -0500838 Returns:
839 A fully resolved symlink path
840 """
841 while os.path.islink(root + path):
842 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
843 return path
844
845
846def _GetFilesForTarget(target, root='/'):
847 """Locate all the files to package for |target|
848
849 This does not cover ELF dependencies.
850
851 Args:
852 target: The toolchain target name
853 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500854
Mike Frysinger35247af2012-11-16 18:58:06 -0500855 Returns:
856 A tuple of a set of all packable paths, and a set of all paths which
857 are also native ELFs
858 """
859 paths = set()
860 elfs = set()
861
862 # Find all the files owned by the packages for this target.
863 for pkg in GetTargetPackages(target):
864 # Ignore packages that are part of the target sysroot.
865 if pkg in ('kernel', 'libc'):
866 continue
867
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700868 # Skip Go compiler from redistributable packages.
869 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
870 # into it. Due to this, the toolchain cannot be unpacked anywhere
871 # else and be readily useful. To enable packaging Go, we need to:
872 # -) Tweak the wrappers/environment to override GOROOT
873 # automatically based on the unpack location.
874 # -) Make sure the ELF dependency checking and wrapping logic
875 # below skips the Go toolchain executables and libraries.
876 # -) Make sure the packaging process maintains the relative
877 # timestamps of precompiled standard library packages.
878 # (see dev-lang/go ebuild for details).
879 if pkg == 'ex_go':
880 continue
881
Mike Frysinger35247af2012-11-16 18:58:06 -0500882 atom = GetPortagePackage(target, pkg)
883 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700884 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700885 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500886
887 # pylint: disable=E1101
888 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
889 settings=portage.settings)
890 contents = dblink.getcontents()
891 for obj in contents:
892 ptype = contents[obj][0]
893 if not IsPathPackagable(ptype, obj):
894 continue
895
896 if ptype == 'obj':
897 # For native ELFs, we need to pull in their dependencies too.
898 if FileIsCrosSdkElf(obj):
899 elfs.add(obj)
900 paths.add(obj)
901
902 return paths, elfs
903
904
905def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500906 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500907 """Link in all packable files and their runtime dependencies
908
909 This also wraps up executable ELFs with helper scripts.
910
911 Args:
912 output_dir: The output directory to store files
913 paths: All the files to include
914 elfs: All the files which are ELFs (a subset of |paths|)
915 ldpaths: A dict of static ldpath information
916 path_rewrite_func: User callback to rewrite paths in output_dir
917 root: The root path to pull all packages/files from
918 """
919 # Link in all the files.
920 sym_paths = []
921 for path in paths:
922 new_path = path_rewrite_func(path)
923 dst = output_dir + new_path
924 osutils.SafeMakedirs(os.path.dirname(dst))
925
926 # Is this a symlink which we have to rewrite or wrap?
927 # Delay wrap check until after we have created all paths.
928 src = root + path
929 if os.path.islink(src):
930 tgt = os.readlink(src)
931 if os.path.sep in tgt:
932 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
933
934 # Rewrite absolute links to relative and then generate the symlink
935 # ourselves. All other symlinks can be hardlinked below.
936 if tgt[0] == '/':
937 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
938 os.symlink(tgt, dst)
939 continue
940
941 os.link(src, dst)
942
943 # Now see if any of the symlinks need to be wrapped.
944 for sym, tgt in sym_paths:
945 if tgt in elfs:
946 GeneratePathWrapper(output_dir, sym, tgt)
947
948 # Locate all the dependencies for all the ELFs. Stick them all in the
949 # top level "lib" dir to make the wrapper simpler. This exact path does
950 # not matter since we execute ldso directly, and we tell the ldso the
951 # exact path to search for its libraries.
952 libdir = os.path.join(output_dir, 'lib')
953 osutils.SafeMakedirs(libdir)
954 donelibs = set()
955 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400956 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500957 interp = e['interp']
958 if interp:
959 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400960 interp = os.path.join('/lib', os.path.basename(interp))
961 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
962 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700963 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500964
965 for lib, lib_data in e['libs'].iteritems():
966 if lib in donelibs:
967 continue
968
969 src = path = lib_data['path']
970 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700971 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500972 continue
973 donelibs.add(lib)
974
975 # Needed libs are the SONAME, but that is usually a symlink, not a
976 # real file. So link in the target rather than the symlink itself.
977 # We have to walk all the possible symlinks (SONAME could point to a
978 # symlink which points to a symlink), and we have to handle absolute
979 # ourselves (since we have a "root" argument).
980 dst = os.path.join(libdir, os.path.basename(path))
981 src = ReadlinkRoot(src, root)
982
983 os.link(root + src, dst)
984
985
986def _EnvdGetVar(envd, var):
987 """Given a Gentoo env.d file, extract a var from it
988
989 Args:
990 envd: The env.d file to load (may be a glob path)
991 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500992
Mike Frysinger35247af2012-11-16 18:58:06 -0500993 Returns:
994 The value of |var|
995 """
996 envds = glob.glob(envd)
997 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
998 envd = envds[0]
999 return cros_build_lib.LoadKeyValueFile(envd)[var]
1000
1001
1002def _ProcessBinutilsConfig(target, output_dir):
1003 """Do what binutils-config would have done"""
1004 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001005
1006 # Locate the bin dir holding the gold linker.
1007 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1008 target, 'binutils-bin')
1009 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001010 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001011 if not srcpath:
1012 # Maybe this target doesn't support gold.
1013 globpath = os.path.join(binutils_bin_path, '*')
1014 srcpath = glob.glob(globpath)
1015 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1016 % globpath)
1017 srcpath = srcpath[0]
1018 ld_path = os.path.join(srcpath, 'ld')
1019 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1020 ld_path = os.path.join(srcpath, 'ld.bfd')
1021 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1022 ld_path = os.path.join(srcpath, 'ld.gold')
1023 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1024 % ld_path)
1025
1026 # Nope, no gold support to be found.
1027 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001028 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001029 else:
1030 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001031 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001032
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001033 # Package the binutils-bin directory without the '-gold' suffix
1034 # if gold is not enabled as the default linker for this target.
1035 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1036 if not gold_supported:
1037 srcpath = srcpath[:-len('-gold')]
1038 ld_path = os.path.join(srcpath, 'ld')
1039 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1040
Mike Frysinger78b7a812014-11-26 19:45:23 -05001041 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001042 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1043 for prog in os.listdir(output_dir + srcpath):
1044 # Skip binaries already wrapped.
1045 if not prog.endswith('.real'):
1046 GeneratePathWrapper(output_dir, binpath + prog,
1047 os.path.join(srcpath, prog))
1048 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1049 os.path.join(srcpath, prog))
1050
David James27ac4ae2012-12-03 23:16:15 -08001051 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001052 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1053 if gold_supported:
1054 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001055 else:
1056 # If gold is not enabled as the default linker and 2 env.d
1057 # files exist, pick the one without the '-gold' suffix.
1058 envds = sorted(glob.glob(envd))
1059 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1060 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001061 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1062 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1063 output_dir + libpath)
1064
1065
1066def _ProcessGccConfig(target, output_dir):
1067 """Do what gcc-config would have done"""
1068 binpath = '/bin'
1069 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1070 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1071 for prog in os.listdir(output_dir + srcpath):
1072 # Skip binaries already wrapped.
1073 if (not prog.endswith('.real') and
1074 not prog.endswith('.elf') and
1075 prog.startswith(target)):
1076 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1077 os.path.join(srcpath, prog))
1078 return srcpath
1079
1080
Frank Henigman179ec7c2015-02-06 03:01:09 -05001081def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1082 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001083 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001084 for sysroot_wrapper in glob.glob(os.path.join(
1085 output_dir + srcpath, 'sysroot_wrapper*')):
1086 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1087 for num in xrange(len(contents)):
1088 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001089 assert 'True' in contents[num]
1090 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001091 break
1092 # Can't update the wrapper in place since it's a hardlink to a file in /.
1093 os.unlink(sysroot_wrapper)
1094 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1095 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001096
1097
1098def _ProcessDistroCleanups(target, output_dir):
1099 """Clean up the tree and remove all distro-specific requirements
1100
1101 Args:
1102 target: The toolchain target name
1103 output_dir: The output directory to clean up
1104 """
1105 _ProcessBinutilsConfig(target, output_dir)
1106 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001107 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001108
1109 osutils.RmDir(os.path.join(output_dir, 'etc'))
1110
1111
1112def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1113 """Setup a tree from the packages for the specified target
1114
1115 This populates a path with all the files from toolchain packages so that
1116 a tarball can easily be generated from the result.
1117
1118 Args:
1119 target: The target to create a packagable root from
1120 output_dir: The output directory to place all the files
1121 ldpaths: A dict of static ldpath information
1122 root: The root path to pull all packages/files from
1123 """
1124 # Find all the files owned by the packages for this target.
1125 paths, elfs = _GetFilesForTarget(target, root=root)
1126
1127 # Link in all the package's files, any ELF dependencies, and wrap any
1128 # executable ELFs with helper scripts.
1129 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001130 """Move /usr/bin to /bin so people can just use that toplevel dir
1131
1132 Note we do not apply this to clang - there is correlation between clang's
1133 search path for libraries / inclusion and its installation path.
1134 """
1135 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1136 return path[4:]
1137 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001138 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1139 path_rewrite_func=MoveUsrBinToBin, root=root)
1140
1141 # The packages, when part of the normal distro, have helper scripts
1142 # that setup paths and such. Since we are making this standalone, we
1143 # need to preprocess all that ourselves.
1144 _ProcessDistroCleanups(target, output_dir)
1145
1146
1147def CreatePackages(targets_wanted, output_dir, root='/'):
1148 """Create redistributable cross-compiler packages for the specified targets
1149
1150 This creates toolchain packages that should be usable in conjunction with
1151 a downloaded sysroot (created elsewhere).
1152
1153 Tarballs (one per target) will be created in $PWD.
1154
1155 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001156 targets_wanted: The targets to package up.
1157 output_dir: The directory to put the packages in.
1158 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001159 """
Ralph Nathan03047282015-03-23 11:09:32 -07001160 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001161 osutils.SafeMakedirs(output_dir)
1162 ldpaths = lddtree.LoadLdpaths(root)
1163 targets = ExpandTargets(targets_wanted)
1164
David James4bc13702013-03-26 08:08:04 -07001165 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001166 # We have to split the root generation from the compression stages. This is
1167 # because we hardlink in all the files (to avoid overhead of reading/writing
1168 # the copies multiple times). But tar gets angry if a file's hardlink count
1169 # changes from when it starts reading a file to when it finishes.
1170 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1171 for target in targets:
1172 output_target_dir = os.path.join(tempdir, target)
1173 queue.put([target, output_target_dir, ldpaths, root])
1174
1175 # Build the tarball.
1176 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1177 for target in targets:
1178 tar_file = os.path.join(output_dir, target + '.tar.xz')
1179 queue.put([tar_file, os.path.join(tempdir, target)])
1180
1181
Brian Harring30675052012-02-29 12:18:22 -08001182def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -05001183 parser = commandline.ArgumentParser(description=__doc__)
1184 parser.add_argument('-u', '--nousepkg',
1185 action='store_false', dest='usepkg', default=True,
1186 help='Use prebuilt packages if possible')
1187 parser.add_argument('-d', '--deleteold',
1188 action='store_true', dest='deleteold', default=False,
1189 help='Unmerge deprecated packages')
1190 parser.add_argument('-t', '--targets',
1191 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001192 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001193 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001194 "allowed. Defaults to 'sdk'.")
1195 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1196 help='Comma separated list of boards whose toolchains we '
1197 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001198 parser.add_argument('--hostonly',
1199 dest='hostonly', default=False, action='store_true',
1200 help='Only setup the host toolchain. '
1201 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001202 parser.add_argument('--show-board-cfg', '--show-cfg',
1203 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001204 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001205 parser.add_argument('--create-packages',
1206 action='store_true', default=False,
1207 help='Build redistributable packages')
1208 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1209 help='Output directory')
1210 parser.add_argument('--reconfig', default=False, action='store_true',
1211 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001212 parser.add_argument('--sysroot', type='path',
1213 help='The sysroot in which to install the toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001214
Mike Frysinger0c808452014-11-06 17:30:23 -05001215 options = parser.parse_args(argv)
1216 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001217
Mike Frysinger35247af2012-11-16 18:58:06 -05001218 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001219 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001220 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001221
Gilad Arnold8195b532015-04-07 10:56:30 +03001222 targets_wanted = set(options.targets.split(','))
1223 boards_wanted = (set(options.include_boards.split(','))
1224 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001225
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001226 if options.cfg_name:
1227 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001228 elif options.create_packages:
1229 cros_build_lib.AssertInsideChroot()
1230 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001231 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001232 else:
1233 cros_build_lib.AssertInsideChroot()
1234 # This has to be always run as root.
1235 if os.geteuid() != 0:
1236 cros_build_lib.Die('this script must be run as root')
1237
1238 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001239 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001240 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001241 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001242 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001243 Crossdev.Save()
1244
1245 return 0