blob: 91074218b7507d92088b487fee0b4b024134bbef [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,
Rahul Chaudhry4b803052015-05-13 15:25:56 -070054 'ex_go' : PACKAGE_NONE,
Manoj Gupta1b5642e2017-03-08 16:44:12 -080055 'ex_compiler-rt': PACKAGE_NONE,
Mike Frysingerd6e2df02014-11-26 02:55:04 -050056 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010057}
Rahul Chaudhry4b803052015-05-13 15:25:56 -070058
59# Enable the Go compiler for these targets.
60TARGET_GO_ENABLED = (
61 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070062 'armv7a-cros-linux-gnueabi',
63)
64CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
65
Manoj Gupta1b5642e2017-03-08 16:44:12 -080066# Enable llvm's compiler-rt for these targets.
67TARGET_COMPILER_RT_ENABLED = (
68 'armv7a-cros-linux-gnueabi',
69)
70CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
71
Zdenek Behan508dcce2011-12-05 15:39:32 +010072# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
73CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050074 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040075 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080076 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050077 'i686-pc-linux-gnu' : '-gold',
78 'x86_64-cros-linux-gnu' : '-gold',
79 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010080}
Zdenek Behan508dcce2011-12-05 15:39:32 +010081# Global per-run cache that will be filled ondemand in by GetPackageMap()
82# function as needed.
83target_version_map = {
84}
85
86
David James66a09c42012-11-05 13:31:38 -080087class Crossdev(object):
88 """Class for interacting with crossdev and caching its output."""
89
90 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
91 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -080092 # Packages that needs separate handling, in addition to what we have from
93 # crossdev.
94 MANUAL_PKGS = {
95 'llvm': 'sys-devel',
96 }
David James66a09c42012-11-05 13:31:38 -080097
98 @classmethod
99 def Load(cls, reconfig):
100 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -0800101 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
102 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -0800103 if os.path.exists(cls._CACHE_FILE) and not reconfig:
104 with open(cls._CACHE_FILE) as f:
105 data = json.load(f)
David James90239b92012-11-05 15:31:34 -0800106 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -0800107 cls._CACHE = data
108
109 @classmethod
110 def Save(cls):
111 """Store crossdev cache on disk."""
112 # Save the cache from the successful run.
113 with open(cls._CACHE_FILE, 'w') as f:
114 json.dump(cls._CACHE, f)
115
116 @classmethod
117 def GetConfig(cls, target):
118 """Returns a map of crossdev provided variables about a tuple."""
119 CACHE_ATTR = '_target_tuple_map'
120
121 val = cls._CACHE.setdefault(CACHE_ATTR, {})
122 if not target in val:
123 # Find out the crossdev tuple.
124 target_tuple = target
125 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800126 target_tuple = toolchain.GetHostTuple()
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700127 # Build the crossdev command.
128 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
129 if target in TARGET_GO_ENABLED:
130 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta1b5642e2017-03-08 16:44:12 -0800131 if target in TARGET_COMPILER_RT_ENABLED:
132 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700133 cmd.extend(['-t', target_tuple])
David James66a09c42012-11-05 13:31:38 -0800134 # Catch output of crossdev.
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700135 out = cros_build_lib.RunCommand(cmd, print_cmd=False,
136 redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800137 # List of tuples split at the first '=', converted into dict.
Han Shene23782f2016-02-18 12:20:00 -0800138 conf = dict((k, cros_build_lib.ShellUnquote(v))
139 for k, v in (x.split('=', 1) for x in out))
140 conf['crosspkgs'] = conf['crosspkgs'].split()
141
142 for pkg, cat in cls.MANUAL_PKGS.iteritems():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400143 conf[pkg + '_pn'] = pkg
144 conf[pkg + '_category'] = cat
145 if pkg not in conf['crosspkgs']:
146 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800147
148 val[target] = conf
149
David James66a09c42012-11-05 13:31:38 -0800150 return val[target]
151
152 @classmethod
153 def UpdateTargets(cls, targets, usepkg, config_only=False):
154 """Calls crossdev to initialize a cross target.
155
156 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700157 targets: The list of targets to initialize using crossdev.
158 usepkg: Copies the commandline opts.
159 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800160 """
161 configured_targets = cls._CACHE.setdefault('configured_targets', [])
162
163 cmdbase = ['crossdev', '--show-fail-log']
164 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
165 # Pick stable by default, and override as necessary.
166 cmdbase.extend(['-P', '--oneshot'])
167 if usepkg:
168 cmdbase.extend(['-P', '--getbinpkg',
169 '-P', '--usepkgonly',
170 '--without-headers'])
171
Christopher Wileyb22c0712015-06-02 10:37:03 -0700172 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800173 cmdbase.extend(['--overlays', overlays])
174 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
175
176 for target in targets:
177 if config_only and target in configured_targets:
178 continue
179
180 cmd = cmdbase + ['-t', target]
181
182 for pkg in GetTargetPackages(target):
183 if pkg == 'gdb':
184 # Gdb does not have selectable versions.
185 cmd.append('--ex-gdb')
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700186 elif pkg == 'ex_go':
187 # Go does not have selectable versions.
188 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta1b5642e2017-03-08 16:44:12 -0800189 elif pkg == 'ex_compiler-rt':
190 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Han Shene23782f2016-02-18 12:20:00 -0800191 elif pkg in cls.MANUAL_PKGS:
192 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700193 else:
194 # The first of the desired versions is the "primary" one.
195 version = GetDesiredPackageVersions(target, pkg)[0]
196 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800197
198 cmd.extend(targets[target]['crossdev'].split())
199 if config_only:
200 # In this case we want to just quietly reinit
201 cmd.append('--init-target')
202 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
203 else:
204 cros_build_lib.RunCommand(cmd)
205
206 configured_targets.append(target)
207
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100208
Zdenek Behan508dcce2011-12-05 15:39:32 +0100209def GetPackageMap(target):
210 """Compiles a package map for the given target from the constants.
211
212 Uses a cache in target_version_map, that is dynamically filled in as needed,
213 since here everything is static data and the structuring is for ease of
214 configurability only.
215
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500216 Args:
217 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100218
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500219 Returns:
220 A map between packages and desired versions in internal format
221 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100222 """
223 if target in target_version_map:
224 return target_version_map[target]
225
226 # Start from copy of the global defaults.
227 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
228
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100229 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100230 # prefer any specific overrides
231 if pkg in TARGET_VERSION_MAP.get(target, {}):
232 result[pkg] = TARGET_VERSION_MAP[target][pkg]
233 else:
234 # finally, if not already set, set a sane default
235 result.setdefault(pkg, DEFAULT_VERSION)
236 target_version_map[target] = result
237 return result
238
239
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100240def GetTargetPackages(target):
241 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800242 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100243 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800244 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100245
246
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100247# Portage helper functions:
248def GetPortagePackage(target, package):
249 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800250 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100251 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800252 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100253 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100254 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100255 category = conf['category']
256 # Portage package:
257 pn = conf[package + '_pn']
258 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500259 assert category
260 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100261 return '%s/%s' % (category, pn)
262
263
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100264def IsPackageDisabled(target, package):
265 """Returns if the given package is not used for the target."""
266 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
267
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100268
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700269def PortageTrees(root):
270 """Return the portage trees for a given root."""
271 if root == '/':
272 return portage.db['/']
273 # The portage logic requires the path always end in a slash.
274 root = root.rstrip('/') + '/'
275 return portage.create_trees(target_root=root, config_root=root)[root]
276
277
278def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100279 """Extracts the list of current versions of a target, package pair.
280
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500281 Args:
282 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700283 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100284
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500285 Returns:
286 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100287 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100288 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500289 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700290 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100291 version = portage.versions.cpv_getversion(pkg)
292 versions.append(version)
293 return versions
294
295
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700296def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100297 """Extracts the current stable version for a given package.
298
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500299 Args:
300 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
301 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700302 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100303
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500304 Returns:
305 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100306 """
David James90239b92012-11-05 15:31:34 -0800307 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500308 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700309 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800310 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100311
312
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700313def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100314 """Resolves keywords in a given version list for a particular package.
315
316 Resolving means replacing PACKAGE_STABLE with the actual number.
317
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500318 Args:
319 target: The target to operate on (e.g. i686-pc-linux-gnu)
320 package: The target/package to operate on (e.g. gcc)
321 versions: List of versions to resolve
322 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700323 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100324
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500325 Returns:
326 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100327 """
328 resolved = []
David James90239b92012-11-05 15:31:34 -0800329 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700330 if not installed:
331 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100332 for version in versions:
333 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700334 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100335 elif version != PACKAGE_NONE:
336 resolved.append(version)
337 return resolved
338
339
340def GetDesiredPackageVersions(target, package):
341 """Produces the list of desired versions for each target, package pair.
342
343 The first version in the list is implicitly treated as primary, ie.
344 the version that will be initialized by crossdev and selected.
345
346 If the version is PACKAGE_STABLE, it really means the current version which
347 is emerged by using the package atom with no particular version key.
348 Since crossdev unmasks all packages by default, this will actually
349 mean 'unstable' in most cases.
350
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500351 Args:
352 target: The target to operate on (e.g. i686-pc-linux-gnu)
353 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100354
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500355 Returns:
356 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100357 """
358 packagemap = GetPackageMap(target)
359
360 versions = []
361 if package in packagemap:
362 versions.append(packagemap[package])
363
364 return versions
365
366
367def TargetIsInitialized(target):
368 """Verifies if the given list of targets has been correctly initialized.
369
370 This determines whether we have to call crossdev while emerging
371 toolchain packages or can do it using emerge. Emerge is naturally
372 preferred, because all packages can be updated in a single pass.
373
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500374 Args:
375 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500377 Returns:
378 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100379 """
380 # Check if packages for the given target all have a proper version.
381 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100382 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800383 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100384 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800385 if not IsPackageDisabled(target, package) and not (
386 GetStablePackageVersion(atom, True) and
387 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100388 return False
389 return True
390 except cros_build_lib.RunCommandError:
391 # Fails - The target has likely never been initialized before.
392 return False
393
394
395def RemovePackageMask(target):
396 """Removes a package.mask file for the given platform.
397
398 The pre-existing package.mask files can mess with the keywords.
399
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500400 Args:
401 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402 """
403 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700404 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100405
406
Zdenek Behan508dcce2011-12-05 15:39:32 +0100407# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700408def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500409 """Rebuild libtool as needed
410
411 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
412 gcc, libtool will break. We can't use binary packages either as those will
413 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700414
415 Args:
416 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500417 """
418 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700419 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500420 for line in f:
421 # Look for a line like:
422 # sys_lib_search_path_spec="..."
423 # It'll be a list of paths and gcc will be one of them.
424 if line.startswith('sys_lib_search_path_spec='):
425 line = line.rstrip()
426 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400427 root_path = os.path.join(root, path.lstrip(os.path.sep))
428 logging.debug('Libtool: checking %s', root_path)
429 if not os.path.exists(root_path):
430 logging.info('Rebuilding libtool after gcc upgrade')
431 logging.info(' %s', line)
432 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500433 needs_update = True
434 break
435
436 if needs_update:
437 break
438
439 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700440 cmd = [EMERGE_CMD, '--oneshot']
441 if root != '/':
442 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
443 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500444 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400445 else:
446 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500447
448
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700449def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100450 """Determines which packages need update/unmerge and defers to portage.
451
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500452 Args:
453 targets: The list of targets to update
454 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700455 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100456 """
David James90239b92012-11-05 15:31:34 -0800457 # Remove keyword files created by old versions of cros_setup_toolchains.
458 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100459
460 # For each target, we do two things. Figure out the list of updates,
461 # and figure out the appropriate keywords/masks. Crossdev will initialize
462 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400463 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800464 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100465 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400466 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100467 # Record the highest needed version for each target, for masking purposes.
468 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100469 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100470 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100471 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400472 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100473 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400474 logging.debug(' Updating package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100475 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700476 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100477 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200478 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100479 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100480
Zdenek Behan508dcce2011-12-05 15:39:32 +0100481 packages = []
482 for pkg in mergemap:
483 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200484 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800485 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100486
487 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400488 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800489 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100490
Mike Frysinger3bba5032016-09-20 14:15:04 -0400491 logging.info('Updating packages:')
492 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100493
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100494 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100495 if usepkg:
496 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700497 if root != '/':
498 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100499
500 cmd.extend(packages)
501 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800502 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100503
504
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700505def CleanTargets(targets, root='/'):
506 """Unmerges old packages that are assumed unnecessary.
507
508 Args:
509 targets: The list of targets to clean up.
510 root: The install root in which we want packages cleaned up.
511 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100512 unmergemap = {}
513 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400514 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100515 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100516 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400517 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100518 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400519 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100520 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700521 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100522 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700523 # NOTE: This refers to installed packages (vartree) rather than the
524 # Portage version (porttree and/or bintree) when determining the current
525 # version. While this isn't the most accurate thing to do, it is probably
526 # a good simple compromise, which should have the desired result of
527 # uninstalling everything but the latest installed version. In
528 # particular, using the bintree (--usebinpkg) requires a non-trivial
529 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200530 desired_num = VersionListToNumeric(target, package, desired, True)
531 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400532 logging.warning('Error detecting stable version for %s, '
533 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200534 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100535 unmergemap[pkg] = set(current).difference(desired_num)
536
537 # Cleaning doesn't care about consistency and rebuilding package.* files.
538 packages = []
539 for pkg, vers in unmergemap.iteritems():
540 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
541
542 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400543 logging.info('Cleaning packages:')
544 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100545 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700546 if root != '/':
547 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100548 cmd.extend(packages)
549 cros_build_lib.RunCommand(cmd)
550 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400551 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100552
553
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700554def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100555 """Runs gcc-config and binutils-config to select the desired.
556
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500557 Args:
558 targets: The targets to select
559 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700560 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100561 """
562 for package in ['gcc', 'binutils']:
563 for target in targets:
564 # Pick the first version in the numbered list as the selected one.
565 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700566 desired_num = VersionListToNumeric(target, package, desired, True,
567 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100568 desired = desired_num[0]
569 # *-config does not play revisions, strip them, keep just PV.
570 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
571
572 if target == 'host':
573 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800574 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100575
576 # And finally, attach target to it.
577 desired = '%s-%s' % (target, desired)
578
579 # Target specific hacks
580 if package in suffixes:
581 if target in suffixes[package]:
582 desired += suffixes[package][target]
583
David James7ec5efc2012-11-06 09:39:49 -0800584 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700585 if root != '/':
586 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800587 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500588 result = cros_build_lib.RunCommand(
589 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
590 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700591
592 # Do not reconfig when the current is live or nothing needs to be done.
593 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100594 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500595 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700596 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100597
598
Mike Frysinger35247af2012-11-16 18:58:06 -0500599def ExpandTargets(targets_wanted):
600 """Expand any possible toolchain aliases into full targets
601
602 This will expand 'all' and 'sdk' into the respective toolchain tuples.
603
604 Args:
605 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500606
Mike Frysinger35247af2012-11-16 18:58:06 -0500607 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300608 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500609 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500610 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700611 if targets_wanted == set(['boards']):
612 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300613 return {}
614
615 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500616 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300617 return all_targets
618 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500619 # Filter out all the non-sdk toolchains as we don't want to mess
620 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300621 return toolchain.FilterToolchains(all_targets, 'sdk', True)
622
623 # Verify user input.
624 nonexistent = targets_wanted.difference(all_targets)
625 if nonexistent:
626 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
627 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500628
629
David Jamesf8c672f2012-11-06 13:38:11 -0800630def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700631 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100632 """Performs all steps to create a synchronized toolchain enviroment.
633
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500634 Args:
635 usepkg: Use prebuilt packages
636 deleteold: Unmerge deprecated packages
637 hostonly: Only setup the host toolchain
638 reconfig: Reload crossdev config and reselect toolchains
639 targets_wanted: All the targets to update
640 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700641 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100642 """
David Jamesf8c672f2012-11-06 13:38:11 -0800643 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100644 if not hostonly:
645 # For hostonly, we can skip most of the below logic, much of which won't
646 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500647 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400648
Don Garrettc0c74002015-10-09 12:58:19 -0700649 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300650 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400651 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800652 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100653
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100654 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400655 for target in targets:
656 if TargetIsInitialized(target):
657 reconfig_targets[target] = targets[target]
658 else:
659 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100660 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400661 logging.info('The following targets need to be re-initialized:')
662 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800663 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200664 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800665 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100666
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100667 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400668 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100669
670 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700671 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
672 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800673
674 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700675 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100676
Mike Frysingerc880a962013-11-08 13:59:06 -0500677 # Now that we've cleared out old versions, see if we need to rebuild
678 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700679 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500680
Zdenek Behan508dcce2011-12-05 15:39:32 +0100681
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700682def ShowConfig(name):
683 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500684
685 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700686 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500687 """
Don Garrettc0c74002015-10-09 12:58:19 -0700688 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500689 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400690 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400691 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800692 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400693 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500694
695
Mike Frysinger35247af2012-11-16 18:58:06 -0500696def GeneratePathWrapper(root, wrappath, path):
697 """Generate a shell script to execute another shell script
698
699 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
700 argv[0] won't be pointing to the correct path, generate a shell script that
701 just executes another program with its full path.
702
703 Args:
704 root: The root tree to generate scripts inside of
705 wrappath: The full path (inside |root|) to create the wrapper
706 path: The target program which this wrapper will execute
707 """
708 replacements = {
709 'path': path,
710 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
711 }
712 wrapper = """#!/bin/sh
713base=$(realpath "$0")
714basedir=${base%%/*}
715exec "${basedir}/%(relroot)s%(path)s" "$@"
716""" % replacements
717 root_wrapper = root + wrappath
718 if os.path.islink(root_wrapper):
719 os.unlink(root_wrapper)
720 else:
721 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
722 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400723 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500724
725
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700726def FixClangXXWrapper(root, path):
727 """Fix wrapper shell scripts and symlinks for invoking clang++
728
729 In a typical installation, clang++ symlinks to clang, which symlinks to the
730 elf executable. The executable distinguishes between clang and clang++ based
731 on argv[0].
732
733 When invoked through the LdsoWrapper, argv[0] always contains the path to the
734 executable elf file, making clang/clang++ invocations indistinguishable.
735
736 This function detects if the elf executable being wrapped is clang-X.Y, and
737 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
738
739 The calling sequence now becomes:
740 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
741 the Ldsowrapper).
742 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
743 to the original clang-3.9 elf.
744 -) The difference this time is that inside the elf file execution, $0 is
745 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
746
747 Args:
748 root: The root tree to generate scripts / symlinks inside of
749 path: The target elf for which LdsoWrapper was created
750 """
751 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
752 logging.info('fixing clang++ invocation for %s', path)
753 clangdir = os.path.dirname(root + path)
754 clang = os.path.basename(path)
755 clangxx = clang.replace('clang', 'clang++')
756
757 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
758 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
759
760 # Create a hardlink clang++-X.Y pointing to clang-X.Y
761 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
762
763 # Adjust the clang++ symlink to point to clang++-X.Y
764 os.unlink(os.path.join(clangdir, 'clang++'))
765 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
766
767
Mike Frysinger35247af2012-11-16 18:58:06 -0500768def FileIsCrosSdkElf(elf):
769 """Determine if |elf| is an ELF that we execute in the cros_sdk
770
771 We don't need this to be perfect, just quick. It makes sure the ELF
772 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
773
774 Args:
775 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500776
Mike Frysinger35247af2012-11-16 18:58:06 -0500777 Returns:
778 True if we think |elf| is a native ELF
779 """
780 with open(elf) as f:
781 data = f.read(20)
782 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
783 return (data[0:4] == '\x7fELF' and
784 data[4] == '\x02' and
785 data[5] == '\x01' and
786 data[18] == '\x3e')
787
788
789def IsPathPackagable(ptype, path):
790 """Should the specified file be included in a toolchain package?
791
792 We only need to handle files as we'll create dirs as we need them.
793
794 Further, trim files that won't be useful:
795 - non-english translations (.mo) since it'd require env vars
796 - debug files since these are for the host compiler itself
797 - info/man pages as they're big, and docs are online, and the
798 native docs should work fine for the most part (`man gcc`)
799
800 Args:
801 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
802 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500803
Mike Frysinger35247af2012-11-16 18:58:06 -0500804 Returns:
805 True if we want to include this path in the package
806 """
807 return not (ptype in ('dir',) or
808 path.startswith('/usr/lib/debug/') or
809 os.path.splitext(path)[1] == '.mo' or
810 ('/man/' in path or '/info/' in path))
811
812
813def ReadlinkRoot(path, root):
814 """Like os.readlink(), but relative to a |root|
815
816 Args:
817 path: The symlink to read
818 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500819
Mike Frysinger35247af2012-11-16 18:58:06 -0500820 Returns:
821 A fully resolved symlink path
822 """
823 while os.path.islink(root + path):
824 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
825 return path
826
827
828def _GetFilesForTarget(target, root='/'):
829 """Locate all the files to package for |target|
830
831 This does not cover ELF dependencies.
832
833 Args:
834 target: The toolchain target name
835 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500836
Mike Frysinger35247af2012-11-16 18:58:06 -0500837 Returns:
838 A tuple of a set of all packable paths, and a set of all paths which
839 are also native ELFs
840 """
841 paths = set()
842 elfs = set()
843
844 # Find all the files owned by the packages for this target.
845 for pkg in GetTargetPackages(target):
846 # Ignore packages that are part of the target sysroot.
847 if pkg in ('kernel', 'libc'):
848 continue
849
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700850 # Skip Go compiler from redistributable packages.
851 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
852 # into it. Due to this, the toolchain cannot be unpacked anywhere
853 # else and be readily useful. To enable packaging Go, we need to:
854 # -) Tweak the wrappers/environment to override GOROOT
855 # automatically based on the unpack location.
856 # -) Make sure the ELF dependency checking and wrapping logic
857 # below skips the Go toolchain executables and libraries.
858 # -) Make sure the packaging process maintains the relative
859 # timestamps of precompiled standard library packages.
860 # (see dev-lang/go ebuild for details).
861 if pkg == 'ex_go':
862 continue
863
Mike Frysinger35247af2012-11-16 18:58:06 -0500864 atom = GetPortagePackage(target, pkg)
865 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700866 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700867 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500868
869 # pylint: disable=E1101
870 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
871 settings=portage.settings)
872 contents = dblink.getcontents()
873 for obj in contents:
874 ptype = contents[obj][0]
875 if not IsPathPackagable(ptype, obj):
876 continue
877
878 if ptype == 'obj':
879 # For native ELFs, we need to pull in their dependencies too.
880 if FileIsCrosSdkElf(obj):
881 elfs.add(obj)
882 paths.add(obj)
883
884 return paths, elfs
885
886
887def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500888 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500889 """Link in all packable files and their runtime dependencies
890
891 This also wraps up executable ELFs with helper scripts.
892
893 Args:
894 output_dir: The output directory to store files
895 paths: All the files to include
896 elfs: All the files which are ELFs (a subset of |paths|)
897 ldpaths: A dict of static ldpath information
898 path_rewrite_func: User callback to rewrite paths in output_dir
899 root: The root path to pull all packages/files from
900 """
901 # Link in all the files.
902 sym_paths = []
903 for path in paths:
904 new_path = path_rewrite_func(path)
905 dst = output_dir + new_path
906 osutils.SafeMakedirs(os.path.dirname(dst))
907
908 # Is this a symlink which we have to rewrite or wrap?
909 # Delay wrap check until after we have created all paths.
910 src = root + path
911 if os.path.islink(src):
912 tgt = os.readlink(src)
913 if os.path.sep in tgt:
914 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
915
916 # Rewrite absolute links to relative and then generate the symlink
917 # ourselves. All other symlinks can be hardlinked below.
918 if tgt[0] == '/':
919 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
920 os.symlink(tgt, dst)
921 continue
922
923 os.link(src, dst)
924
925 # Now see if any of the symlinks need to be wrapped.
926 for sym, tgt in sym_paths:
927 if tgt in elfs:
928 GeneratePathWrapper(output_dir, sym, tgt)
929
930 # Locate all the dependencies for all the ELFs. Stick them all in the
931 # top level "lib" dir to make the wrapper simpler. This exact path does
932 # not matter since we execute ldso directly, and we tell the ldso the
933 # exact path to search for its libraries.
934 libdir = os.path.join(output_dir, 'lib')
935 osutils.SafeMakedirs(libdir)
936 donelibs = set()
937 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400938 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500939 interp = e['interp']
940 if interp:
941 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400942 interp = os.path.join('/lib', os.path.basename(interp))
943 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
944 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700945 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500946
947 for lib, lib_data in e['libs'].iteritems():
948 if lib in donelibs:
949 continue
950
951 src = path = lib_data['path']
952 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700953 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500954 continue
955 donelibs.add(lib)
956
957 # Needed libs are the SONAME, but that is usually a symlink, not a
958 # real file. So link in the target rather than the symlink itself.
959 # We have to walk all the possible symlinks (SONAME could point to a
960 # symlink which points to a symlink), and we have to handle absolute
961 # ourselves (since we have a "root" argument).
962 dst = os.path.join(libdir, os.path.basename(path))
963 src = ReadlinkRoot(src, root)
964
965 os.link(root + src, dst)
966
967
968def _EnvdGetVar(envd, var):
969 """Given a Gentoo env.d file, extract a var from it
970
971 Args:
972 envd: The env.d file to load (may be a glob path)
973 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500974
Mike Frysinger35247af2012-11-16 18:58:06 -0500975 Returns:
976 The value of |var|
977 """
978 envds = glob.glob(envd)
979 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
980 envd = envds[0]
981 return cros_build_lib.LoadKeyValueFile(envd)[var]
982
983
984def _ProcessBinutilsConfig(target, output_dir):
985 """Do what binutils-config would have done"""
986 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500987
988 # Locate the bin dir holding the gold linker.
989 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
990 target, 'binutils-bin')
991 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500992 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500993 if not srcpath:
994 # Maybe this target doesn't support gold.
995 globpath = os.path.join(binutils_bin_path, '*')
996 srcpath = glob.glob(globpath)
997 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
998 % globpath)
999 srcpath = srcpath[0]
1000 ld_path = os.path.join(srcpath, 'ld')
1001 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1002 ld_path = os.path.join(srcpath, 'ld.bfd')
1003 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1004 ld_path = os.path.join(srcpath, 'ld.gold')
1005 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1006 % ld_path)
1007
1008 # Nope, no gold support to be found.
1009 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001010 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001011 else:
1012 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001013 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001014
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001015 # Package the binutils-bin directory without the '-gold' suffix
1016 # if gold is not enabled as the default linker for this target.
1017 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1018 if not gold_supported:
1019 srcpath = srcpath[:-len('-gold')]
1020 ld_path = os.path.join(srcpath, 'ld')
1021 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1022
Mike Frysinger78b7a812014-11-26 19:45:23 -05001023 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001024 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1025 for prog in os.listdir(output_dir + srcpath):
1026 # Skip binaries already wrapped.
1027 if not prog.endswith('.real'):
1028 GeneratePathWrapper(output_dir, binpath + prog,
1029 os.path.join(srcpath, prog))
1030 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1031 os.path.join(srcpath, prog))
1032
David James27ac4ae2012-12-03 23:16:15 -08001033 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001034 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1035 if gold_supported:
1036 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001037 else:
1038 # If gold is not enabled as the default linker and 2 env.d
1039 # files exist, pick the one without the '-gold' suffix.
1040 envds = sorted(glob.glob(envd))
1041 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1042 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001043 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1044 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1045 output_dir + libpath)
1046
1047
1048def _ProcessGccConfig(target, output_dir):
1049 """Do what gcc-config would have done"""
1050 binpath = '/bin'
1051 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1052 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1053 for prog in os.listdir(output_dir + srcpath):
1054 # Skip binaries already wrapped.
1055 if (not prog.endswith('.real') and
1056 not prog.endswith('.elf') and
1057 prog.startswith(target)):
1058 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1059 os.path.join(srcpath, prog))
1060 return srcpath
1061
1062
Frank Henigman179ec7c2015-02-06 03:01:09 -05001063def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1064 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001065 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001066 for sysroot_wrapper in glob.glob(os.path.join(
1067 output_dir + srcpath, 'sysroot_wrapper*')):
1068 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1069 for num in xrange(len(contents)):
1070 if '@CCACHE_DEFAULT@' in contents[num]:
1071 contents[num] = 'use_ccache = False'
1072 break
1073 # Can't update the wrapper in place since it's a hardlink to a file in /.
1074 os.unlink(sysroot_wrapper)
1075 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1076 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001077
1078
1079def _ProcessDistroCleanups(target, output_dir):
1080 """Clean up the tree and remove all distro-specific requirements
1081
1082 Args:
1083 target: The toolchain target name
1084 output_dir: The output directory to clean up
1085 """
1086 _ProcessBinutilsConfig(target, output_dir)
1087 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001088 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001089
1090 osutils.RmDir(os.path.join(output_dir, 'etc'))
1091
1092
1093def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1094 """Setup a tree from the packages for the specified target
1095
1096 This populates a path with all the files from toolchain packages so that
1097 a tarball can easily be generated from the result.
1098
1099 Args:
1100 target: The target to create a packagable root from
1101 output_dir: The output directory to place all the files
1102 ldpaths: A dict of static ldpath information
1103 root: The root path to pull all packages/files from
1104 """
1105 # Find all the files owned by the packages for this target.
1106 paths, elfs = _GetFilesForTarget(target, root=root)
1107
1108 # Link in all the package's files, any ELF dependencies, and wrap any
1109 # executable ELFs with helper scripts.
1110 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001111 """Move /usr/bin to /bin so people can just use that toplevel dir
1112
1113 Note we do not apply this to clang - there is correlation between clang's
1114 search path for libraries / inclusion and its installation path.
1115 """
1116 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1117 return path[4:]
1118 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001119 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1120 path_rewrite_func=MoveUsrBinToBin, root=root)
1121
1122 # The packages, when part of the normal distro, have helper scripts
1123 # that setup paths and such. Since we are making this standalone, we
1124 # need to preprocess all that ourselves.
1125 _ProcessDistroCleanups(target, output_dir)
1126
1127
1128def CreatePackages(targets_wanted, output_dir, root='/'):
1129 """Create redistributable cross-compiler packages for the specified targets
1130
1131 This creates toolchain packages that should be usable in conjunction with
1132 a downloaded sysroot (created elsewhere).
1133
1134 Tarballs (one per target) will be created in $PWD.
1135
1136 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001137 targets_wanted: The targets to package up.
1138 output_dir: The directory to put the packages in.
1139 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001140 """
Ralph Nathan03047282015-03-23 11:09:32 -07001141 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001142 osutils.SafeMakedirs(output_dir)
1143 ldpaths = lddtree.LoadLdpaths(root)
1144 targets = ExpandTargets(targets_wanted)
1145
David James4bc13702013-03-26 08:08:04 -07001146 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001147 # We have to split the root generation from the compression stages. This is
1148 # because we hardlink in all the files (to avoid overhead of reading/writing
1149 # the copies multiple times). But tar gets angry if a file's hardlink count
1150 # changes from when it starts reading a file to when it finishes.
1151 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1152 for target in targets:
1153 output_target_dir = os.path.join(tempdir, target)
1154 queue.put([target, output_target_dir, ldpaths, root])
1155
1156 # Build the tarball.
1157 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1158 for target in targets:
1159 tar_file = os.path.join(output_dir, target + '.tar.xz')
1160 queue.put([tar_file, os.path.join(tempdir, target)])
1161
1162
Brian Harring30675052012-02-29 12:18:22 -08001163def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -05001164 parser = commandline.ArgumentParser(description=__doc__)
1165 parser.add_argument('-u', '--nousepkg',
1166 action='store_false', dest='usepkg', default=True,
1167 help='Use prebuilt packages if possible')
1168 parser.add_argument('-d', '--deleteold',
1169 action='store_true', dest='deleteold', default=False,
1170 help='Unmerge deprecated packages')
1171 parser.add_argument('-t', '--targets',
1172 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001173 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001174 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001175 "allowed. Defaults to 'sdk'.")
1176 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1177 help='Comma separated list of boards whose toolchains we '
1178 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001179 parser.add_argument('--hostonly',
1180 dest='hostonly', default=False, action='store_true',
1181 help='Only setup the host toolchain. '
1182 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001183 parser.add_argument('--show-board-cfg', '--show-cfg',
1184 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001185 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001186 parser.add_argument('--create-packages',
1187 action='store_true', default=False,
1188 help='Build redistributable packages')
1189 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1190 help='Output directory')
1191 parser.add_argument('--reconfig', default=False, action='store_true',
1192 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001193 parser.add_argument('--sysroot', type='path',
1194 help='The sysroot in which to install the toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001195
Mike Frysinger0c808452014-11-06 17:30:23 -05001196 options = parser.parse_args(argv)
1197 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001198
Mike Frysinger35247af2012-11-16 18:58:06 -05001199 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001200 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001201 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001202
Gilad Arnold8195b532015-04-07 10:56:30 +03001203 targets_wanted = set(options.targets.split(','))
1204 boards_wanted = (set(options.include_boards.split(','))
1205 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001206
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001207 if options.cfg_name:
1208 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001209 elif options.create_packages:
1210 cros_build_lib.AssertInsideChroot()
1211 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001212 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001213 else:
1214 cros_build_lib.AssertInsideChroot()
1215 # This has to be always run as root.
1216 if os.geteuid() != 0:
1217 cros_build_lib.Die('this script must be run as root')
1218
1219 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001220 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001221 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001222 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001223 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001224 Crossdev.Save()
1225
1226 return 0