blob: 667f8b5292b688bca0cc3d6df1a861978456f145 [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 = {
105 'llvm': 'sys-devel',
106 }
David James66a09c42012-11-05 13:31:38 -0800107
108 @classmethod
109 def Load(cls, reconfig):
110 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -0800111 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
112 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -0800113 if os.path.exists(cls._CACHE_FILE) and not reconfig:
114 with open(cls._CACHE_FILE) as f:
115 data = json.load(f)
David James90239b92012-11-05 15:31:34 -0800116 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -0800117 cls._CACHE = data
118
119 @classmethod
120 def Save(cls):
121 """Store crossdev cache on disk."""
122 # Save the cache from the successful run.
123 with open(cls._CACHE_FILE, 'w') as f:
124 json.dump(cls._CACHE, f)
125
126 @classmethod
127 def GetConfig(cls, target):
128 """Returns a map of crossdev provided variables about a tuple."""
129 CACHE_ATTR = '_target_tuple_map'
130
131 val = cls._CACHE.setdefault(CACHE_ATTR, {})
132 if not target in val:
133 # Find out the crossdev tuple.
134 target_tuple = target
135 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800136 target_tuple = toolchain.GetHostTuple()
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700137 # Build the crossdev command.
138 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
Manoj Gupta1b5642e2017-03-08 16:44:12 -0800139 if target in TARGET_COMPILER_RT_ENABLED:
140 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Manoj Guptab8181562017-05-21 10:18:59 -0700141 if target in TARGET_GO_ENABLED:
142 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700143 if target in TARGET_LLVM_PKGS_ENABLED:
144 for pkg in LLVM_PKGS_TABLE:
145 cmd.extend(LLVM_PKGS_TABLE[pkg])
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700146 cmd.extend(['-t', target_tuple])
David James66a09c42012-11-05 13:31:38 -0800147 # Catch output of crossdev.
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700148 out = cros_build_lib.RunCommand(cmd, print_cmd=False,
149 redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800150 # List of tuples split at the first '=', converted into dict.
Han Shene23782f2016-02-18 12:20:00 -0800151 conf = dict((k, cros_build_lib.ShellUnquote(v))
152 for k, v in (x.split('=', 1) for x in out))
153 conf['crosspkgs'] = conf['crosspkgs'].split()
154
155 for pkg, cat in cls.MANUAL_PKGS.iteritems():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400156 conf[pkg + '_pn'] = pkg
157 conf[pkg + '_category'] = cat
158 if pkg not in conf['crosspkgs']:
159 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800160
161 val[target] = conf
162
David James66a09c42012-11-05 13:31:38 -0800163 return val[target]
164
165 @classmethod
166 def UpdateTargets(cls, targets, usepkg, config_only=False):
167 """Calls crossdev to initialize a cross target.
168
169 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700170 targets: The list of targets to initialize using crossdev.
171 usepkg: Copies the commandline opts.
172 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800173 """
174 configured_targets = cls._CACHE.setdefault('configured_targets', [])
175
176 cmdbase = ['crossdev', '--show-fail-log']
177 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
178 # Pick stable by default, and override as necessary.
179 cmdbase.extend(['-P', '--oneshot'])
180 if usepkg:
181 cmdbase.extend(['-P', '--getbinpkg',
182 '-P', '--usepkgonly',
183 '--without-headers'])
184
Christopher Wileyb22c0712015-06-02 10:37:03 -0700185 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800186 cmdbase.extend(['--overlays', overlays])
187 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
188
189 for target in targets:
190 if config_only and target in configured_targets:
191 continue
192
193 cmd = cmdbase + ['-t', target]
194
195 for pkg in GetTargetPackages(target):
196 if pkg == 'gdb':
197 # Gdb does not have selectable versions.
198 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700199 elif pkg == 'ex_compiler-rt':
200 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700201 elif pkg == 'ex_go':
202 # Go does not have selectable versions.
203 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700204 elif pkg in LLVM_PKGS_TABLE:
205 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800206 elif pkg in cls.MANUAL_PKGS:
207 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700208 else:
209 # The first of the desired versions is the "primary" one.
210 version = GetDesiredPackageVersions(target, pkg)[0]
211 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800212
213 cmd.extend(targets[target]['crossdev'].split())
214 if config_only:
215 # In this case we want to just quietly reinit
216 cmd.append('--init-target')
217 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
218 else:
219 cros_build_lib.RunCommand(cmd)
220
221 configured_targets.append(target)
222
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100223
Zdenek Behan508dcce2011-12-05 15:39:32 +0100224def GetPackageMap(target):
225 """Compiles a package map for the given target from the constants.
226
227 Uses a cache in target_version_map, that is dynamically filled in as needed,
228 since here everything is static data and the structuring is for ease of
229 configurability only.
230
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500231 Args:
232 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100233
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500234 Returns:
235 A map between packages and desired versions in internal format
236 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100237 """
238 if target in target_version_map:
239 return target_version_map[target]
240
241 # Start from copy of the global defaults.
242 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
243
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100244 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100245 # prefer any specific overrides
246 if pkg in TARGET_VERSION_MAP.get(target, {}):
247 result[pkg] = TARGET_VERSION_MAP[target][pkg]
248 else:
249 # finally, if not already set, set a sane default
250 result.setdefault(pkg, DEFAULT_VERSION)
251 target_version_map[target] = result
252 return result
253
254
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100255def GetTargetPackages(target):
256 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800257 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100258 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800259 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100260
261
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100262# Portage helper functions:
263def GetPortagePackage(target, package):
264 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800265 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100266 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800267 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100268 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100269 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100270 category = conf['category']
271 # Portage package:
272 pn = conf[package + '_pn']
273 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500274 assert category
275 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100276 return '%s/%s' % (category, pn)
277
278
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100279def IsPackageDisabled(target, package):
280 """Returns if the given package is not used for the target."""
281 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
282
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100283
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700284def PortageTrees(root):
285 """Return the portage trees for a given root."""
286 if root == '/':
287 return portage.db['/']
288 # The portage logic requires the path always end in a slash.
289 root = root.rstrip('/') + '/'
290 return portage.create_trees(target_root=root, config_root=root)[root]
291
292
293def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100294 """Extracts the list of current versions of a target, package pair.
295
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500296 Args:
297 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700298 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100299
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500300 Returns:
301 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100302 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100303 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500304 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700305 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100306 version = portage.versions.cpv_getversion(pkg)
307 versions.append(version)
308 return versions
309
310
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700311def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100312 """Extracts the current stable version for a given package.
313
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500314 Args:
315 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
316 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700317 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100318
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500319 Returns:
320 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100321 """
David James90239b92012-11-05 15:31:34 -0800322 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500323 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700324 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800325 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100326
327
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700328def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100329 """Resolves keywords in a given version list for a particular package.
330
331 Resolving means replacing PACKAGE_STABLE with the actual number.
332
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500333 Args:
334 target: The target to operate on (e.g. i686-pc-linux-gnu)
335 package: The target/package to operate on (e.g. gcc)
336 versions: List of versions to resolve
337 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700338 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100339
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500340 Returns:
341 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100342 """
343 resolved = []
David James90239b92012-11-05 15:31:34 -0800344 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700345 if not installed:
346 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100347 for version in versions:
348 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700349 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100350 elif version != PACKAGE_NONE:
351 resolved.append(version)
352 return resolved
353
354
355def GetDesiredPackageVersions(target, package):
356 """Produces the list of desired versions for each target, package pair.
357
358 The first version in the list is implicitly treated as primary, ie.
359 the version that will be initialized by crossdev and selected.
360
361 If the version is PACKAGE_STABLE, it really means the current version which
362 is emerged by using the package atom with no particular version key.
363 Since crossdev unmasks all packages by default, this will actually
364 mean 'unstable' in most cases.
365
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500366 Args:
367 target: The target to operate on (e.g. i686-pc-linux-gnu)
368 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100369
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500370 Returns:
371 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100372 """
373 packagemap = GetPackageMap(target)
374
375 versions = []
376 if package in packagemap:
377 versions.append(packagemap[package])
378
379 return versions
380
381
382def TargetIsInitialized(target):
383 """Verifies if the given list of targets has been correctly initialized.
384
385 This determines whether we have to call crossdev while emerging
386 toolchain packages or can do it using emerge. Emerge is naturally
387 preferred, because all packages can be updated in a single pass.
388
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500389 Args:
390 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100391
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500392 Returns:
393 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394 """
395 # Check if packages for the given target all have a proper version.
396 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100397 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800398 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100399 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800400 if not IsPackageDisabled(target, package) and not (
401 GetStablePackageVersion(atom, True) and
402 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100403 return False
404 return True
405 except cros_build_lib.RunCommandError:
406 # Fails - The target has likely never been initialized before.
407 return False
408
409
410def RemovePackageMask(target):
411 """Removes a package.mask file for the given platform.
412
413 The pre-existing package.mask files can mess with the keywords.
414
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500415 Args:
416 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100417 """
418 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700419 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100420
421
Zdenek Behan508dcce2011-12-05 15:39:32 +0100422# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700423def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500424 """Rebuild libtool as needed
425
426 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
427 gcc, libtool will break. We can't use binary packages either as those will
428 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700429
430 Args:
431 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500432 """
433 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700434 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500435 for line in f:
436 # Look for a line like:
437 # sys_lib_search_path_spec="..."
438 # It'll be a list of paths and gcc will be one of them.
439 if line.startswith('sys_lib_search_path_spec='):
440 line = line.rstrip()
441 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400442 root_path = os.path.join(root, path.lstrip(os.path.sep))
443 logging.debug('Libtool: checking %s', root_path)
444 if not os.path.exists(root_path):
445 logging.info('Rebuilding libtool after gcc upgrade')
446 logging.info(' %s', line)
447 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500448 needs_update = True
449 break
450
451 if needs_update:
452 break
453
454 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700455 cmd = [EMERGE_CMD, '--oneshot']
456 if root != '/':
457 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
458 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500459 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400460 else:
461 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500462
463
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700464def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100465 """Determines which packages need update/unmerge and defers to portage.
466
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500467 Args:
468 targets: The list of targets to update
469 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700470 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100471 """
David James90239b92012-11-05 15:31:34 -0800472 # Remove keyword files created by old versions of cros_setup_toolchains.
473 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100474
475 # For each target, we do two things. Figure out the list of updates,
476 # and figure out the appropriate keywords/masks. Crossdev will initialize
477 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400478 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800479 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100480 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400481 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100482 # Record the highest needed version for each target, for masking purposes.
483 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100484 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100485 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100486 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400487 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100488 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400489 logging.debug(' Updating package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100490 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700491 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100492 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200493 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100494 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100495
Zdenek Behan508dcce2011-12-05 15:39:32 +0100496 packages = []
497 for pkg in mergemap:
498 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200499 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800500 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100501
502 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400503 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800504 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100505
Mike Frysinger3bba5032016-09-20 14:15:04 -0400506 logging.info('Updating packages:')
507 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100508
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100509 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100510 if usepkg:
511 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700512 if root != '/':
513 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100514
515 cmd.extend(packages)
516 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800517 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100518
519
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700520def CleanTargets(targets, root='/'):
521 """Unmerges old packages that are assumed unnecessary.
522
523 Args:
524 targets: The list of targets to clean up.
525 root: The install root in which we want packages cleaned up.
526 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100527 unmergemap = {}
528 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400529 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100530 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100531 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400532 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100533 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400534 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100535 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700536 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100537 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700538 # NOTE: This refers to installed packages (vartree) rather than the
539 # Portage version (porttree and/or bintree) when determining the current
540 # version. While this isn't the most accurate thing to do, it is probably
541 # a good simple compromise, which should have the desired result of
542 # uninstalling everything but the latest installed version. In
543 # particular, using the bintree (--usebinpkg) requires a non-trivial
544 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200545 desired_num = VersionListToNumeric(target, package, desired, True)
546 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400547 logging.warning('Error detecting stable version for %s, '
548 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200549 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100550 unmergemap[pkg] = set(current).difference(desired_num)
551
552 # Cleaning doesn't care about consistency and rebuilding package.* files.
553 packages = []
554 for pkg, vers in unmergemap.iteritems():
555 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
556
557 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400558 logging.info('Cleaning packages:')
559 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100560 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700561 if root != '/':
562 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100563 cmd.extend(packages)
564 cros_build_lib.RunCommand(cmd)
565 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400566 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100567
568
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700569def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100570 """Runs gcc-config and binutils-config to select the desired.
571
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500572 Args:
573 targets: The targets to select
574 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700575 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100576 """
577 for package in ['gcc', 'binutils']:
578 for target in targets:
579 # Pick the first version in the numbered list as the selected one.
580 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700581 desired_num = VersionListToNumeric(target, package, desired, True,
582 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100583 desired = desired_num[0]
584 # *-config does not play revisions, strip them, keep just PV.
585 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
586
587 if target == 'host':
588 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800589 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100590
591 # And finally, attach target to it.
592 desired = '%s-%s' % (target, desired)
593
594 # Target specific hacks
595 if package in suffixes:
596 if target in suffixes[package]:
597 desired += suffixes[package][target]
598
David James7ec5efc2012-11-06 09:39:49 -0800599 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700600 if root != '/':
601 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800602 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500603 result = cros_build_lib.RunCommand(
604 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
605 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700606
607 # Do not reconfig when the current is live or nothing needs to be done.
608 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100609 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500610 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700611 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100612
613
Mike Frysinger35247af2012-11-16 18:58:06 -0500614def ExpandTargets(targets_wanted):
615 """Expand any possible toolchain aliases into full targets
616
617 This will expand 'all' and 'sdk' into the respective toolchain tuples.
618
619 Args:
620 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500621
Mike Frysinger35247af2012-11-16 18:58:06 -0500622 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300623 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500624 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500625 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700626 if targets_wanted == set(['boards']):
627 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300628 return {}
629
630 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500631 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300632 return all_targets
633 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500634 # Filter out all the non-sdk toolchains as we don't want to mess
635 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300636 return toolchain.FilterToolchains(all_targets, 'sdk', True)
637
638 # Verify user input.
639 nonexistent = targets_wanted.difference(all_targets)
640 if nonexistent:
641 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
642 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500643
644
David Jamesf8c672f2012-11-06 13:38:11 -0800645def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700646 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100647 """Performs all steps to create a synchronized toolchain enviroment.
648
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500649 Args:
650 usepkg: Use prebuilt packages
651 deleteold: Unmerge deprecated packages
652 hostonly: Only setup the host toolchain
653 reconfig: Reload crossdev config and reselect toolchains
654 targets_wanted: All the targets to update
655 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700656 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100657 """
David Jamesf8c672f2012-11-06 13:38:11 -0800658 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100659 if not hostonly:
660 # For hostonly, we can skip most of the below logic, much of which won't
661 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500662 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400663
Don Garrettc0c74002015-10-09 12:58:19 -0700664 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300665 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400666 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800667 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100668
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100669 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400670 for target in targets:
671 if TargetIsInitialized(target):
672 reconfig_targets[target] = targets[target]
673 else:
674 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100675 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400676 logging.info('The following targets need to be re-initialized:')
677 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800678 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200679 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800680 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100681
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100682 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400683 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100684
685 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700686 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
687 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800688
689 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700690 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100691
Mike Frysingerc880a962013-11-08 13:59:06 -0500692 # Now that we've cleared out old versions, see if we need to rebuild
693 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700694 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500695
Zdenek Behan508dcce2011-12-05 15:39:32 +0100696
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700697def ShowConfig(name):
698 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500699
700 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700701 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500702 """
Don Garrettc0c74002015-10-09 12:58:19 -0700703 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500704 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400705 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400706 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800707 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400708 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500709
710
Mike Frysinger35247af2012-11-16 18:58:06 -0500711def GeneratePathWrapper(root, wrappath, path):
712 """Generate a shell script to execute another shell script
713
714 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
715 argv[0] won't be pointing to the correct path, generate a shell script that
716 just executes another program with its full path.
717
718 Args:
719 root: The root tree to generate scripts inside of
720 wrappath: The full path (inside |root|) to create the wrapper
721 path: The target program which this wrapper will execute
722 """
723 replacements = {
724 'path': path,
725 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
726 }
727 wrapper = """#!/bin/sh
728base=$(realpath "$0")
729basedir=${base%%/*}
730exec "${basedir}/%(relroot)s%(path)s" "$@"
731""" % replacements
732 root_wrapper = root + wrappath
733 if os.path.islink(root_wrapper):
734 os.unlink(root_wrapper)
735 else:
736 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
737 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400738 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500739
740
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700741def FixClangXXWrapper(root, path):
742 """Fix wrapper shell scripts and symlinks for invoking clang++
743
744 In a typical installation, clang++ symlinks to clang, which symlinks to the
745 elf executable. The executable distinguishes between clang and clang++ based
746 on argv[0].
747
748 When invoked through the LdsoWrapper, argv[0] always contains the path to the
749 executable elf file, making clang/clang++ invocations indistinguishable.
750
751 This function detects if the elf executable being wrapped is clang-X.Y, and
752 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
753
754 The calling sequence now becomes:
755 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
756 the Ldsowrapper).
757 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
758 to the original clang-3.9 elf.
759 -) The difference this time is that inside the elf file execution, $0 is
760 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
761
762 Args:
763 root: The root tree to generate scripts / symlinks inside of
764 path: The target elf for which LdsoWrapper was created
765 """
766 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
767 logging.info('fixing clang++ invocation for %s', path)
768 clangdir = os.path.dirname(root + path)
769 clang = os.path.basename(path)
770 clangxx = clang.replace('clang', 'clang++')
771
772 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
773 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
774
775 # Create a hardlink clang++-X.Y pointing to clang-X.Y
776 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
777
778 # Adjust the clang++ symlink to point to clang++-X.Y
779 os.unlink(os.path.join(clangdir, 'clang++'))
780 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
781
782
Mike Frysinger35247af2012-11-16 18:58:06 -0500783def FileIsCrosSdkElf(elf):
784 """Determine if |elf| is an ELF that we execute in the cros_sdk
785
786 We don't need this to be perfect, just quick. It makes sure the ELF
787 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
788
789 Args:
790 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500791
Mike Frysinger35247af2012-11-16 18:58:06 -0500792 Returns:
793 True if we think |elf| is a native ELF
794 """
795 with open(elf) as f:
796 data = f.read(20)
797 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
798 return (data[0:4] == '\x7fELF' and
799 data[4] == '\x02' and
800 data[5] == '\x01' and
801 data[18] == '\x3e')
802
803
804def IsPathPackagable(ptype, path):
805 """Should the specified file be included in a toolchain package?
806
807 We only need to handle files as we'll create dirs as we need them.
808
809 Further, trim files that won't be useful:
810 - non-english translations (.mo) since it'd require env vars
811 - debug files since these are for the host compiler itself
812 - info/man pages as they're big, and docs are online, and the
813 native docs should work fine for the most part (`man gcc`)
814
815 Args:
816 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
817 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500818
Mike Frysinger35247af2012-11-16 18:58:06 -0500819 Returns:
820 True if we want to include this path in the package
821 """
822 return not (ptype in ('dir',) or
823 path.startswith('/usr/lib/debug/') or
824 os.path.splitext(path)[1] == '.mo' or
825 ('/man/' in path or '/info/' in path))
826
827
828def ReadlinkRoot(path, root):
829 """Like os.readlink(), but relative to a |root|
830
831 Args:
832 path: The symlink to read
833 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500834
Mike Frysinger35247af2012-11-16 18:58:06 -0500835 Returns:
836 A fully resolved symlink path
837 """
838 while os.path.islink(root + path):
839 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
840 return path
841
842
843def _GetFilesForTarget(target, root='/'):
844 """Locate all the files to package for |target|
845
846 This does not cover ELF dependencies.
847
848 Args:
849 target: The toolchain target name
850 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500851
Mike Frysinger35247af2012-11-16 18:58:06 -0500852 Returns:
853 A tuple of a set of all packable paths, and a set of all paths which
854 are also native ELFs
855 """
856 paths = set()
857 elfs = set()
858
859 # Find all the files owned by the packages for this target.
860 for pkg in GetTargetPackages(target):
861 # Ignore packages that are part of the target sysroot.
862 if pkg in ('kernel', 'libc'):
863 continue
864
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700865 # Skip Go compiler from redistributable packages.
866 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
867 # into it. Due to this, the toolchain cannot be unpacked anywhere
868 # else and be readily useful. To enable packaging Go, we need to:
869 # -) Tweak the wrappers/environment to override GOROOT
870 # automatically based on the unpack location.
871 # -) Make sure the ELF dependency checking and wrapping logic
872 # below skips the Go toolchain executables and libraries.
873 # -) Make sure the packaging process maintains the relative
874 # timestamps of precompiled standard library packages.
875 # (see dev-lang/go ebuild for details).
876 if pkg == 'ex_go':
877 continue
878
Mike Frysinger35247af2012-11-16 18:58:06 -0500879 atom = GetPortagePackage(target, pkg)
880 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700881 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700882 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500883
884 # pylint: disable=E1101
885 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
886 settings=portage.settings)
887 contents = dblink.getcontents()
888 for obj in contents:
889 ptype = contents[obj][0]
890 if not IsPathPackagable(ptype, obj):
891 continue
892
893 if ptype == 'obj':
894 # For native ELFs, we need to pull in their dependencies too.
895 if FileIsCrosSdkElf(obj):
896 elfs.add(obj)
897 paths.add(obj)
898
899 return paths, elfs
900
901
902def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500903 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500904 """Link in all packable files and their runtime dependencies
905
906 This also wraps up executable ELFs with helper scripts.
907
908 Args:
909 output_dir: The output directory to store files
910 paths: All the files to include
911 elfs: All the files which are ELFs (a subset of |paths|)
912 ldpaths: A dict of static ldpath information
913 path_rewrite_func: User callback to rewrite paths in output_dir
914 root: The root path to pull all packages/files from
915 """
916 # Link in all the files.
917 sym_paths = []
918 for path in paths:
919 new_path = path_rewrite_func(path)
920 dst = output_dir + new_path
921 osutils.SafeMakedirs(os.path.dirname(dst))
922
923 # Is this a symlink which we have to rewrite or wrap?
924 # Delay wrap check until after we have created all paths.
925 src = root + path
926 if os.path.islink(src):
927 tgt = os.readlink(src)
928 if os.path.sep in tgt:
929 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
930
931 # Rewrite absolute links to relative and then generate the symlink
932 # ourselves. All other symlinks can be hardlinked below.
933 if tgt[0] == '/':
934 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
935 os.symlink(tgt, dst)
936 continue
937
938 os.link(src, dst)
939
940 # Now see if any of the symlinks need to be wrapped.
941 for sym, tgt in sym_paths:
942 if tgt in elfs:
943 GeneratePathWrapper(output_dir, sym, tgt)
944
945 # Locate all the dependencies for all the ELFs. Stick them all in the
946 # top level "lib" dir to make the wrapper simpler. This exact path does
947 # not matter since we execute ldso directly, and we tell the ldso the
948 # exact path to search for its libraries.
949 libdir = os.path.join(output_dir, 'lib')
950 osutils.SafeMakedirs(libdir)
951 donelibs = set()
952 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400953 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500954 interp = e['interp']
955 if interp:
956 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400957 interp = os.path.join('/lib', os.path.basename(interp))
958 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
959 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700960 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500961
962 for lib, lib_data in e['libs'].iteritems():
963 if lib in donelibs:
964 continue
965
966 src = path = lib_data['path']
967 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700968 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500969 continue
970 donelibs.add(lib)
971
972 # Needed libs are the SONAME, but that is usually a symlink, not a
973 # real file. So link in the target rather than the symlink itself.
974 # We have to walk all the possible symlinks (SONAME could point to a
975 # symlink which points to a symlink), and we have to handle absolute
976 # ourselves (since we have a "root" argument).
977 dst = os.path.join(libdir, os.path.basename(path))
978 src = ReadlinkRoot(src, root)
979
980 os.link(root + src, dst)
981
982
983def _EnvdGetVar(envd, var):
984 """Given a Gentoo env.d file, extract a var from it
985
986 Args:
987 envd: The env.d file to load (may be a glob path)
988 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500989
Mike Frysinger35247af2012-11-16 18:58:06 -0500990 Returns:
991 The value of |var|
992 """
993 envds = glob.glob(envd)
994 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
995 envd = envds[0]
996 return cros_build_lib.LoadKeyValueFile(envd)[var]
997
998
999def _ProcessBinutilsConfig(target, output_dir):
1000 """Do what binutils-config would have done"""
1001 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001002
1003 # Locate the bin dir holding the gold linker.
1004 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1005 target, 'binutils-bin')
1006 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001007 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001008 if not srcpath:
1009 # Maybe this target doesn't support gold.
1010 globpath = os.path.join(binutils_bin_path, '*')
1011 srcpath = glob.glob(globpath)
1012 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1013 % globpath)
1014 srcpath = srcpath[0]
1015 ld_path = os.path.join(srcpath, 'ld')
1016 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1017 ld_path = os.path.join(srcpath, 'ld.bfd')
1018 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1019 ld_path = os.path.join(srcpath, 'ld.gold')
1020 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1021 % ld_path)
1022
1023 # Nope, no gold support to be found.
1024 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001025 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001026 else:
1027 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001028 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001029
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001030 # Package the binutils-bin directory without the '-gold' suffix
1031 # if gold is not enabled as the default linker for this target.
1032 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1033 if not gold_supported:
1034 srcpath = srcpath[:-len('-gold')]
1035 ld_path = os.path.join(srcpath, 'ld')
1036 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1037
Mike Frysinger78b7a812014-11-26 19:45:23 -05001038 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001039 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1040 for prog in os.listdir(output_dir + srcpath):
1041 # Skip binaries already wrapped.
1042 if not prog.endswith('.real'):
1043 GeneratePathWrapper(output_dir, binpath + prog,
1044 os.path.join(srcpath, prog))
1045 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1046 os.path.join(srcpath, prog))
1047
David James27ac4ae2012-12-03 23:16:15 -08001048 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001049 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1050 if gold_supported:
1051 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001052 else:
1053 # If gold is not enabled as the default linker and 2 env.d
1054 # files exist, pick the one without the '-gold' suffix.
1055 envds = sorted(glob.glob(envd))
1056 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1057 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001058 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1059 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1060 output_dir + libpath)
1061
1062
1063def _ProcessGccConfig(target, output_dir):
1064 """Do what gcc-config would have done"""
1065 binpath = '/bin'
1066 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1067 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1068 for prog in os.listdir(output_dir + srcpath):
1069 # Skip binaries already wrapped.
1070 if (not prog.endswith('.real') and
1071 not prog.endswith('.elf') and
1072 prog.startswith(target)):
1073 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1074 os.path.join(srcpath, prog))
1075 return srcpath
1076
1077
Frank Henigman179ec7c2015-02-06 03:01:09 -05001078def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1079 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001080 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001081 for sysroot_wrapper in glob.glob(os.path.join(
1082 output_dir + srcpath, 'sysroot_wrapper*')):
1083 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1084 for num in xrange(len(contents)):
1085 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001086 assert 'True' in contents[num]
1087 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001088 break
1089 # Can't update the wrapper in place since it's a hardlink to a file in /.
1090 os.unlink(sysroot_wrapper)
1091 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1092 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001093
1094
1095def _ProcessDistroCleanups(target, output_dir):
1096 """Clean up the tree and remove all distro-specific requirements
1097
1098 Args:
1099 target: The toolchain target name
1100 output_dir: The output directory to clean up
1101 """
1102 _ProcessBinutilsConfig(target, output_dir)
1103 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001104 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001105
1106 osutils.RmDir(os.path.join(output_dir, 'etc'))
1107
1108
1109def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1110 """Setup a tree from the packages for the specified target
1111
1112 This populates a path with all the files from toolchain packages so that
1113 a tarball can easily be generated from the result.
1114
1115 Args:
1116 target: The target to create a packagable root from
1117 output_dir: The output directory to place all the files
1118 ldpaths: A dict of static ldpath information
1119 root: The root path to pull all packages/files from
1120 """
1121 # Find all the files owned by the packages for this target.
1122 paths, elfs = _GetFilesForTarget(target, root=root)
1123
1124 # Link in all the package's files, any ELF dependencies, and wrap any
1125 # executable ELFs with helper scripts.
1126 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001127 """Move /usr/bin to /bin so people can just use that toplevel dir
1128
1129 Note we do not apply this to clang - there is correlation between clang's
1130 search path for libraries / inclusion and its installation path.
1131 """
1132 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1133 return path[4:]
1134 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001135 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1136 path_rewrite_func=MoveUsrBinToBin, root=root)
1137
1138 # The packages, when part of the normal distro, have helper scripts
1139 # that setup paths and such. Since we are making this standalone, we
1140 # need to preprocess all that ourselves.
1141 _ProcessDistroCleanups(target, output_dir)
1142
1143
1144def CreatePackages(targets_wanted, output_dir, root='/'):
1145 """Create redistributable cross-compiler packages for the specified targets
1146
1147 This creates toolchain packages that should be usable in conjunction with
1148 a downloaded sysroot (created elsewhere).
1149
1150 Tarballs (one per target) will be created in $PWD.
1151
1152 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001153 targets_wanted: The targets to package up.
1154 output_dir: The directory to put the packages in.
1155 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001156 """
Ralph Nathan03047282015-03-23 11:09:32 -07001157 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001158 osutils.SafeMakedirs(output_dir)
1159 ldpaths = lddtree.LoadLdpaths(root)
1160 targets = ExpandTargets(targets_wanted)
1161
David James4bc13702013-03-26 08:08:04 -07001162 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001163 # We have to split the root generation from the compression stages. This is
1164 # because we hardlink in all the files (to avoid overhead of reading/writing
1165 # the copies multiple times). But tar gets angry if a file's hardlink count
1166 # changes from when it starts reading a file to when it finishes.
1167 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1168 for target in targets:
1169 output_target_dir = os.path.join(tempdir, target)
1170 queue.put([target, output_target_dir, ldpaths, root])
1171
1172 # Build the tarball.
1173 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1174 for target in targets:
1175 tar_file = os.path.join(output_dir, target + '.tar.xz')
1176 queue.put([tar_file, os.path.join(tempdir, target)])
1177
1178
Brian Harring30675052012-02-29 12:18:22 -08001179def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -05001180 parser = commandline.ArgumentParser(description=__doc__)
1181 parser.add_argument('-u', '--nousepkg',
1182 action='store_false', dest='usepkg', default=True,
1183 help='Use prebuilt packages if possible')
1184 parser.add_argument('-d', '--deleteold',
1185 action='store_true', dest='deleteold', default=False,
1186 help='Unmerge deprecated packages')
1187 parser.add_argument('-t', '--targets',
1188 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001189 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001190 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001191 "allowed. Defaults to 'sdk'.")
1192 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1193 help='Comma separated list of boards whose toolchains we '
1194 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001195 parser.add_argument('--hostonly',
1196 dest='hostonly', default=False, action='store_true',
1197 help='Only setup the host toolchain. '
1198 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001199 parser.add_argument('--show-board-cfg', '--show-cfg',
1200 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001201 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001202 parser.add_argument('--create-packages',
1203 action='store_true', default=False,
1204 help='Build redistributable packages')
1205 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1206 help='Output directory')
1207 parser.add_argument('--reconfig', default=False, action='store_true',
1208 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001209 parser.add_argument('--sysroot', type='path',
1210 help='The sysroot in which to install the toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001211
Mike Frysinger0c808452014-11-06 17:30:23 -05001212 options = parser.parse_args(argv)
1213 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001214
Mike Frysinger35247af2012-11-16 18:58:06 -05001215 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001216 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001217 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001218
Gilad Arnold8195b532015-04-07 10:56:30 +03001219 targets_wanted = set(options.targets.split(','))
1220 boards_wanted = (set(options.include_boards.split(','))
1221 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001222
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001223 if options.cfg_name:
1224 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001225 elif options.create_packages:
1226 cros_build_lib.AssertInsideChroot()
1227 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001228 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001229 else:
1230 cros_build_lib.AssertInsideChroot()
1231 # This has to be always run as root.
1232 if os.geteuid() != 0:
1233 cros_build_lib.Die('this script must be run as root')
1234
1235 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001236 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001237 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001238 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001239 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001240 Crossdev.Save()
1241
1242 return 0