blob: e8c742af35a2b8602f92159a5924f9eb93eb04fd [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,
Mike Frysingerd6e2df02014-11-26 02:55:04 -050055 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010056}
Rahul Chaudhry4b803052015-05-13 15:25:56 -070057
58# Enable the Go compiler for these targets.
59TARGET_GO_ENABLED = (
60 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070061 'armv7a-cros-linux-gnueabi',
62)
63CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
64
Zdenek Behan508dcce2011-12-05 15:39:32 +010065# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
66CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050067 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040068 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080069 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050070 'i686-pc-linux-gnu' : '-gold',
71 'x86_64-cros-linux-gnu' : '-gold',
72 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010073}
Zdenek Behan508dcce2011-12-05 15:39:32 +010074# Global per-run cache that will be filled ondemand in by GetPackageMap()
75# function as needed.
76target_version_map = {
77}
78
79
David James66a09c42012-11-05 13:31:38 -080080class Crossdev(object):
81 """Class for interacting with crossdev and caching its output."""
82
83 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
84 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -080085 # Packages that needs separate handling, in addition to what we have from
86 # crossdev.
87 MANUAL_PKGS = {
88 'llvm': 'sys-devel',
89 }
David James66a09c42012-11-05 13:31:38 -080090
91 @classmethod
92 def Load(cls, reconfig):
93 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080094 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
95 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080096 if os.path.exists(cls._CACHE_FILE) and not reconfig:
97 with open(cls._CACHE_FILE) as f:
98 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080099 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -0800100 cls._CACHE = data
101
102 @classmethod
103 def Save(cls):
104 """Store crossdev cache on disk."""
105 # Save the cache from the successful run.
106 with open(cls._CACHE_FILE, 'w') as f:
107 json.dump(cls._CACHE, f)
108
109 @classmethod
110 def GetConfig(cls, target):
111 """Returns a map of crossdev provided variables about a tuple."""
112 CACHE_ATTR = '_target_tuple_map'
113
114 val = cls._CACHE.setdefault(CACHE_ATTR, {})
115 if not target in val:
116 # Find out the crossdev tuple.
117 target_tuple = target
118 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800119 target_tuple = toolchain.GetHostTuple()
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700120 # Build the crossdev command.
121 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
122 if target in TARGET_GO_ENABLED:
123 cmd.extend(CROSSDEV_GO_ARGS)
124 cmd.extend(['-t', target_tuple])
David James66a09c42012-11-05 13:31:38 -0800125 # Catch output of crossdev.
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700126 out = cros_build_lib.RunCommand(cmd, print_cmd=False,
127 redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800128 # List of tuples split at the first '=', converted into dict.
Han Shene23782f2016-02-18 12:20:00 -0800129 conf = dict((k, cros_build_lib.ShellUnquote(v))
130 for k, v in (x.split('=', 1) for x in out))
131 conf['crosspkgs'] = conf['crosspkgs'].split()
132
133 for pkg, cat in cls.MANUAL_PKGS.iteritems():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400134 conf[pkg + '_pn'] = pkg
135 conf[pkg + '_category'] = cat
136 if pkg not in conf['crosspkgs']:
137 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800138
139 val[target] = conf
140
David James66a09c42012-11-05 13:31:38 -0800141 return val[target]
142
143 @classmethod
144 def UpdateTargets(cls, targets, usepkg, config_only=False):
145 """Calls crossdev to initialize a cross target.
146
147 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700148 targets: The list of targets to initialize using crossdev.
149 usepkg: Copies the commandline opts.
150 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800151 """
152 configured_targets = cls._CACHE.setdefault('configured_targets', [])
153
154 cmdbase = ['crossdev', '--show-fail-log']
155 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
156 # Pick stable by default, and override as necessary.
157 cmdbase.extend(['-P', '--oneshot'])
158 if usepkg:
159 cmdbase.extend(['-P', '--getbinpkg',
160 '-P', '--usepkgonly',
161 '--without-headers'])
162
Christopher Wileyb22c0712015-06-02 10:37:03 -0700163 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800164 cmdbase.extend(['--overlays', overlays])
165 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
166
167 for target in targets:
168 if config_only and target in configured_targets:
169 continue
170
171 cmd = cmdbase + ['-t', target]
172
173 for pkg in GetTargetPackages(target):
174 if pkg == 'gdb':
175 # Gdb does not have selectable versions.
176 cmd.append('--ex-gdb')
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700177 elif pkg == 'ex_go':
178 # Go does not have selectable versions.
179 cmd.extend(CROSSDEV_GO_ARGS)
Han Shene23782f2016-02-18 12:20:00 -0800180 elif pkg in cls.MANUAL_PKGS:
181 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700182 else:
183 # The first of the desired versions is the "primary" one.
184 version = GetDesiredPackageVersions(target, pkg)[0]
185 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800186
187 cmd.extend(targets[target]['crossdev'].split())
188 if config_only:
189 # In this case we want to just quietly reinit
190 cmd.append('--init-target')
191 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
192 else:
193 cros_build_lib.RunCommand(cmd)
194
195 configured_targets.append(target)
196
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100197
Zdenek Behan508dcce2011-12-05 15:39:32 +0100198def GetPackageMap(target):
199 """Compiles a package map for the given target from the constants.
200
201 Uses a cache in target_version_map, that is dynamically filled in as needed,
202 since here everything is static data and the structuring is for ease of
203 configurability only.
204
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500205 Args:
206 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100207
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500208 Returns:
209 A map between packages and desired versions in internal format
210 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100211 """
212 if target in target_version_map:
213 return target_version_map[target]
214
215 # Start from copy of the global defaults.
216 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
217
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100218 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100219 # prefer any specific overrides
220 if pkg in TARGET_VERSION_MAP.get(target, {}):
221 result[pkg] = TARGET_VERSION_MAP[target][pkg]
222 else:
223 # finally, if not already set, set a sane default
224 result.setdefault(pkg, DEFAULT_VERSION)
225 target_version_map[target] = result
226 return result
227
228
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100229def GetTargetPackages(target):
230 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800231 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100232 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800233 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100234
235
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100236# Portage helper functions:
237def GetPortagePackage(target, package):
238 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800239 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100240 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800241 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100242 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100243 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100244 category = conf['category']
245 # Portage package:
246 pn = conf[package + '_pn']
247 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500248 assert category
249 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100250 return '%s/%s' % (category, pn)
251
252
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100253def IsPackageDisabled(target, package):
254 """Returns if the given package is not used for the target."""
255 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
256
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100257
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700258def PortageTrees(root):
259 """Return the portage trees for a given root."""
260 if root == '/':
261 return portage.db['/']
262 # The portage logic requires the path always end in a slash.
263 root = root.rstrip('/') + '/'
264 return portage.create_trees(target_root=root, config_root=root)[root]
265
266
267def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100268 """Extracts the list of current versions of a target, package pair.
269
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500270 Args:
271 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700272 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100273
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500274 Returns:
275 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100276 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100277 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500278 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700279 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100280 version = portage.versions.cpv_getversion(pkg)
281 versions.append(version)
282 return versions
283
284
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700285def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100286 """Extracts the current stable version for a given package.
287
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500288 Args:
289 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
290 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700291 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100292
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500293 Returns:
294 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100295 """
David James90239b92012-11-05 15:31:34 -0800296 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500297 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700298 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800299 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100300
301
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700302def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100303 """Resolves keywords in a given version list for a particular package.
304
305 Resolving means replacing PACKAGE_STABLE with the actual number.
306
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500307 Args:
308 target: The target to operate on (e.g. i686-pc-linux-gnu)
309 package: The target/package to operate on (e.g. gcc)
310 versions: List of versions to resolve
311 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700312 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100313
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500314 Returns:
315 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100316 """
317 resolved = []
David James90239b92012-11-05 15:31:34 -0800318 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700319 if not installed:
320 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100321 for version in versions:
322 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700323 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100324 elif version != PACKAGE_NONE:
325 resolved.append(version)
326 return resolved
327
328
329def GetDesiredPackageVersions(target, package):
330 """Produces the list of desired versions for each target, package pair.
331
332 The first version in the list is implicitly treated as primary, ie.
333 the version that will be initialized by crossdev and selected.
334
335 If the version is PACKAGE_STABLE, it really means the current version which
336 is emerged by using the package atom with no particular version key.
337 Since crossdev unmasks all packages by default, this will actually
338 mean 'unstable' in most cases.
339
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500340 Args:
341 target: The target to operate on (e.g. i686-pc-linux-gnu)
342 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100343
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500344 Returns:
345 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100346 """
347 packagemap = GetPackageMap(target)
348
349 versions = []
350 if package in packagemap:
351 versions.append(packagemap[package])
352
353 return versions
354
355
356def TargetIsInitialized(target):
357 """Verifies if the given list of targets has been correctly initialized.
358
359 This determines whether we have to call crossdev while emerging
360 toolchain packages or can do it using emerge. Emerge is naturally
361 preferred, because all packages can be updated in a single pass.
362
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500363 Args:
364 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100365
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500366 Returns:
367 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100368 """
369 # Check if packages for the given target all have a proper version.
370 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100371 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800372 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100373 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800374 if not IsPackageDisabled(target, package) and not (
375 GetStablePackageVersion(atom, True) and
376 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100377 return False
378 return True
379 except cros_build_lib.RunCommandError:
380 # Fails - The target has likely never been initialized before.
381 return False
382
383
384def RemovePackageMask(target):
385 """Removes a package.mask file for the given platform.
386
387 The pre-existing package.mask files can mess with the keywords.
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 """
392 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700393 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394
395
Zdenek Behan508dcce2011-12-05 15:39:32 +0100396# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700397def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500398 """Rebuild libtool as needed
399
400 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
401 gcc, libtool will break. We can't use binary packages either as those will
402 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700403
404 Args:
405 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500406 """
407 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700408 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500409 for line in f:
410 # Look for a line like:
411 # sys_lib_search_path_spec="..."
412 # It'll be a list of paths and gcc will be one of them.
413 if line.startswith('sys_lib_search_path_spec='):
414 line = line.rstrip()
415 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400416 root_path = os.path.join(root, path.lstrip(os.path.sep))
417 logging.debug('Libtool: checking %s', root_path)
418 if not os.path.exists(root_path):
419 logging.info('Rebuilding libtool after gcc upgrade')
420 logging.info(' %s', line)
421 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500422 needs_update = True
423 break
424
425 if needs_update:
426 break
427
428 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700429 cmd = [EMERGE_CMD, '--oneshot']
430 if root != '/':
431 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
432 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500433 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400434 else:
435 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500436
437
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700438def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100439 """Determines which packages need update/unmerge and defers to portage.
440
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500441 Args:
442 targets: The list of targets to update
443 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700444 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100445 """
David James90239b92012-11-05 15:31:34 -0800446 # Remove keyword files created by old versions of cros_setup_toolchains.
447 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100448
449 # For each target, we do two things. Figure out the list of updates,
450 # and figure out the appropriate keywords/masks. Crossdev will initialize
451 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400452 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800453 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100454 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400455 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100456 # Record the highest needed version for each target, for masking purposes.
457 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100458 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100459 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100460 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400461 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100462 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400463 logging.debug(' Updating package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100464 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700465 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100466 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200467 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100468 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100469
Zdenek Behan508dcce2011-12-05 15:39:32 +0100470 packages = []
471 for pkg in mergemap:
472 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200473 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800474 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100475
476 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400477 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800478 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100479
Mike Frysinger3bba5032016-09-20 14:15:04 -0400480 logging.info('Updating packages:')
481 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100482
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100483 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100484 if usepkg:
485 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700486 if root != '/':
487 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100488
489 cmd.extend(packages)
490 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800491 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100492
493
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700494def CleanTargets(targets, root='/'):
495 """Unmerges old packages that are assumed unnecessary.
496
497 Args:
498 targets: The list of targets to clean up.
499 root: The install root in which we want packages cleaned up.
500 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100501 unmergemap = {}
502 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400503 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100504 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100505 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400506 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100507 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400508 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100509 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700510 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100511 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700512 # NOTE: This refers to installed packages (vartree) rather than the
513 # Portage version (porttree and/or bintree) when determining the current
514 # version. While this isn't the most accurate thing to do, it is probably
515 # a good simple compromise, which should have the desired result of
516 # uninstalling everything but the latest installed version. In
517 # particular, using the bintree (--usebinpkg) requires a non-trivial
518 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200519 desired_num = VersionListToNumeric(target, package, desired, True)
520 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400521 logging.warning('Error detecting stable version for %s, '
522 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200523 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100524 unmergemap[pkg] = set(current).difference(desired_num)
525
526 # Cleaning doesn't care about consistency and rebuilding package.* files.
527 packages = []
528 for pkg, vers in unmergemap.iteritems():
529 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
530
531 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400532 logging.info('Cleaning packages:')
533 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100534 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700535 if root != '/':
536 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100537 cmd.extend(packages)
538 cros_build_lib.RunCommand(cmd)
539 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400540 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100541
542
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700543def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544 """Runs gcc-config and binutils-config to select the desired.
545
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500546 Args:
547 targets: The targets to select
548 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700549 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100550 """
551 for package in ['gcc', 'binutils']:
552 for target in targets:
553 # Pick the first version in the numbered list as the selected one.
554 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700555 desired_num = VersionListToNumeric(target, package, desired, True,
556 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100557 desired = desired_num[0]
558 # *-config does not play revisions, strip them, keep just PV.
559 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
560
561 if target == 'host':
562 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800563 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564
565 # And finally, attach target to it.
566 desired = '%s-%s' % (target, desired)
567
568 # Target specific hacks
569 if package in suffixes:
570 if target in suffixes[package]:
571 desired += suffixes[package][target]
572
David James7ec5efc2012-11-06 09:39:49 -0800573 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700574 if root != '/':
575 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800576 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500577 result = cros_build_lib.RunCommand(
578 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
579 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700580
581 # Do not reconfig when the current is live or nothing needs to be done.
582 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100583 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500584 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700585 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100586
587
Mike Frysinger35247af2012-11-16 18:58:06 -0500588def ExpandTargets(targets_wanted):
589 """Expand any possible toolchain aliases into full targets
590
591 This will expand 'all' and 'sdk' into the respective toolchain tuples.
592
593 Args:
594 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500595
Mike Frysinger35247af2012-11-16 18:58:06 -0500596 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300597 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500598 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500599 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700600 if targets_wanted == set(['boards']):
601 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300602 return {}
603
604 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500605 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300606 return all_targets
607 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500608 # Filter out all the non-sdk toolchains as we don't want to mess
609 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300610 return toolchain.FilterToolchains(all_targets, 'sdk', True)
611
612 # Verify user input.
613 nonexistent = targets_wanted.difference(all_targets)
614 if nonexistent:
615 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
616 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500617
618
David Jamesf8c672f2012-11-06 13:38:11 -0800619def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700620 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100621 """Performs all steps to create a synchronized toolchain enviroment.
622
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500623 Args:
624 usepkg: Use prebuilt packages
625 deleteold: Unmerge deprecated packages
626 hostonly: Only setup the host toolchain
627 reconfig: Reload crossdev config and reselect toolchains
628 targets_wanted: All the targets to update
629 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700630 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100631 """
David Jamesf8c672f2012-11-06 13:38:11 -0800632 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100633 if not hostonly:
634 # For hostonly, we can skip most of the below logic, much of which won't
635 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500636 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400637
Don Garrettc0c74002015-10-09 12:58:19 -0700638 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300639 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400640 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800641 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100642
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100643 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400644 for target in targets:
645 if TargetIsInitialized(target):
646 reconfig_targets[target] = targets[target]
647 else:
648 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100649 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400650 logging.info('The following targets need to be re-initialized:')
651 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800652 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200653 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800654 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100655
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100656 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400657 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100658
659 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700660 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
661 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800662
663 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700664 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100665
Mike Frysingerc880a962013-11-08 13:59:06 -0500666 # Now that we've cleared out old versions, see if we need to rebuild
667 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700668 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500669
Zdenek Behan508dcce2011-12-05 15:39:32 +0100670
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700671def ShowConfig(name):
672 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500673
674 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700675 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500676 """
Don Garrettc0c74002015-10-09 12:58:19 -0700677 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500678 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400679 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400680 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800681 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400682 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500683
684
Mike Frysinger35247af2012-11-16 18:58:06 -0500685def GeneratePathWrapper(root, wrappath, path):
686 """Generate a shell script to execute another shell script
687
688 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
689 argv[0] won't be pointing to the correct path, generate a shell script that
690 just executes another program with its full path.
691
692 Args:
693 root: The root tree to generate scripts inside of
694 wrappath: The full path (inside |root|) to create the wrapper
695 path: The target program which this wrapper will execute
696 """
697 replacements = {
698 'path': path,
699 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
700 }
701 wrapper = """#!/bin/sh
702base=$(realpath "$0")
703basedir=${base%%/*}
704exec "${basedir}/%(relroot)s%(path)s" "$@"
705""" % replacements
706 root_wrapper = root + wrappath
707 if os.path.islink(root_wrapper):
708 os.unlink(root_wrapper)
709 else:
710 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
711 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400712 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500713
714
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700715def FixClangXXWrapper(root, path):
716 """Fix wrapper shell scripts and symlinks for invoking clang++
717
718 In a typical installation, clang++ symlinks to clang, which symlinks to the
719 elf executable. The executable distinguishes between clang and clang++ based
720 on argv[0].
721
722 When invoked through the LdsoWrapper, argv[0] always contains the path to the
723 executable elf file, making clang/clang++ invocations indistinguishable.
724
725 This function detects if the elf executable being wrapped is clang-X.Y, and
726 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
727
728 The calling sequence now becomes:
729 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
730 the Ldsowrapper).
731 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
732 to the original clang-3.9 elf.
733 -) The difference this time is that inside the elf file execution, $0 is
734 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
735
736 Args:
737 root: The root tree to generate scripts / symlinks inside of
738 path: The target elf for which LdsoWrapper was created
739 """
740 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
741 logging.info('fixing clang++ invocation for %s', path)
742 clangdir = os.path.dirname(root + path)
743 clang = os.path.basename(path)
744 clangxx = clang.replace('clang', 'clang++')
745
746 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
747 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
748
749 # Create a hardlink clang++-X.Y pointing to clang-X.Y
750 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
751
752 # Adjust the clang++ symlink to point to clang++-X.Y
753 os.unlink(os.path.join(clangdir, 'clang++'))
754 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
755
756
Mike Frysinger35247af2012-11-16 18:58:06 -0500757def FileIsCrosSdkElf(elf):
758 """Determine if |elf| is an ELF that we execute in the cros_sdk
759
760 We don't need this to be perfect, just quick. It makes sure the ELF
761 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
762
763 Args:
764 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500765
Mike Frysinger35247af2012-11-16 18:58:06 -0500766 Returns:
767 True if we think |elf| is a native ELF
768 """
769 with open(elf) as f:
770 data = f.read(20)
771 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
772 return (data[0:4] == '\x7fELF' and
773 data[4] == '\x02' and
774 data[5] == '\x01' and
775 data[18] == '\x3e')
776
777
778def IsPathPackagable(ptype, path):
779 """Should the specified file be included in a toolchain package?
780
781 We only need to handle files as we'll create dirs as we need them.
782
783 Further, trim files that won't be useful:
784 - non-english translations (.mo) since it'd require env vars
785 - debug files since these are for the host compiler itself
786 - info/man pages as they're big, and docs are online, and the
787 native docs should work fine for the most part (`man gcc`)
788
789 Args:
790 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
791 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500792
Mike Frysinger35247af2012-11-16 18:58:06 -0500793 Returns:
794 True if we want to include this path in the package
795 """
796 return not (ptype in ('dir',) or
797 path.startswith('/usr/lib/debug/') or
798 os.path.splitext(path)[1] == '.mo' or
799 ('/man/' in path or '/info/' in path))
800
801
802def ReadlinkRoot(path, root):
803 """Like os.readlink(), but relative to a |root|
804
805 Args:
806 path: The symlink to read
807 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500808
Mike Frysinger35247af2012-11-16 18:58:06 -0500809 Returns:
810 A fully resolved symlink path
811 """
812 while os.path.islink(root + path):
813 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
814 return path
815
816
817def _GetFilesForTarget(target, root='/'):
818 """Locate all the files to package for |target|
819
820 This does not cover ELF dependencies.
821
822 Args:
823 target: The toolchain target name
824 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500825
Mike Frysinger35247af2012-11-16 18:58:06 -0500826 Returns:
827 A tuple of a set of all packable paths, and a set of all paths which
828 are also native ELFs
829 """
830 paths = set()
831 elfs = set()
832
833 # Find all the files owned by the packages for this target.
834 for pkg in GetTargetPackages(target):
835 # Ignore packages that are part of the target sysroot.
836 if pkg in ('kernel', 'libc'):
837 continue
838
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700839 # Skip Go compiler from redistributable packages.
840 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
841 # into it. Due to this, the toolchain cannot be unpacked anywhere
842 # else and be readily useful. To enable packaging Go, we need to:
843 # -) Tweak the wrappers/environment to override GOROOT
844 # automatically based on the unpack location.
845 # -) Make sure the ELF dependency checking and wrapping logic
846 # below skips the Go toolchain executables and libraries.
847 # -) Make sure the packaging process maintains the relative
848 # timestamps of precompiled standard library packages.
849 # (see dev-lang/go ebuild for details).
850 if pkg == 'ex_go':
851 continue
852
Mike Frysinger35247af2012-11-16 18:58:06 -0500853 atom = GetPortagePackage(target, pkg)
854 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700855 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700856 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500857
858 # pylint: disable=E1101
859 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
860 settings=portage.settings)
861 contents = dblink.getcontents()
862 for obj in contents:
863 ptype = contents[obj][0]
864 if not IsPathPackagable(ptype, obj):
865 continue
866
867 if ptype == 'obj':
868 # For native ELFs, we need to pull in their dependencies too.
869 if FileIsCrosSdkElf(obj):
870 elfs.add(obj)
871 paths.add(obj)
872
873 return paths, elfs
874
875
876def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500877 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500878 """Link in all packable files and their runtime dependencies
879
880 This also wraps up executable ELFs with helper scripts.
881
882 Args:
883 output_dir: The output directory to store files
884 paths: All the files to include
885 elfs: All the files which are ELFs (a subset of |paths|)
886 ldpaths: A dict of static ldpath information
887 path_rewrite_func: User callback to rewrite paths in output_dir
888 root: The root path to pull all packages/files from
889 """
890 # Link in all the files.
891 sym_paths = []
892 for path in paths:
893 new_path = path_rewrite_func(path)
894 dst = output_dir + new_path
895 osutils.SafeMakedirs(os.path.dirname(dst))
896
897 # Is this a symlink which we have to rewrite or wrap?
898 # Delay wrap check until after we have created all paths.
899 src = root + path
900 if os.path.islink(src):
901 tgt = os.readlink(src)
902 if os.path.sep in tgt:
903 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
904
905 # Rewrite absolute links to relative and then generate the symlink
906 # ourselves. All other symlinks can be hardlinked below.
907 if tgt[0] == '/':
908 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
909 os.symlink(tgt, dst)
910 continue
911
912 os.link(src, dst)
913
914 # Now see if any of the symlinks need to be wrapped.
915 for sym, tgt in sym_paths:
916 if tgt in elfs:
917 GeneratePathWrapper(output_dir, sym, tgt)
918
919 # Locate all the dependencies for all the ELFs. Stick them all in the
920 # top level "lib" dir to make the wrapper simpler. This exact path does
921 # not matter since we execute ldso directly, and we tell the ldso the
922 # exact path to search for its libraries.
923 libdir = os.path.join(output_dir, 'lib')
924 osutils.SafeMakedirs(libdir)
925 donelibs = set()
926 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400927 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500928 interp = e['interp']
929 if interp:
930 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400931 interp = os.path.join('/lib', os.path.basename(interp))
932 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
933 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700934 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500935
936 for lib, lib_data in e['libs'].iteritems():
937 if lib in donelibs:
938 continue
939
940 src = path = lib_data['path']
941 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700942 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500943 continue
944 donelibs.add(lib)
945
946 # Needed libs are the SONAME, but that is usually a symlink, not a
947 # real file. So link in the target rather than the symlink itself.
948 # We have to walk all the possible symlinks (SONAME could point to a
949 # symlink which points to a symlink), and we have to handle absolute
950 # ourselves (since we have a "root" argument).
951 dst = os.path.join(libdir, os.path.basename(path))
952 src = ReadlinkRoot(src, root)
953
954 os.link(root + src, dst)
955
956
957def _EnvdGetVar(envd, var):
958 """Given a Gentoo env.d file, extract a var from it
959
960 Args:
961 envd: The env.d file to load (may be a glob path)
962 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500963
Mike Frysinger35247af2012-11-16 18:58:06 -0500964 Returns:
965 The value of |var|
966 """
967 envds = glob.glob(envd)
968 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
969 envd = envds[0]
970 return cros_build_lib.LoadKeyValueFile(envd)[var]
971
972
973def _ProcessBinutilsConfig(target, output_dir):
974 """Do what binutils-config would have done"""
975 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500976
977 # Locate the bin dir holding the gold linker.
978 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
979 target, 'binutils-bin')
980 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500981 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500982 if not srcpath:
983 # Maybe this target doesn't support gold.
984 globpath = os.path.join(binutils_bin_path, '*')
985 srcpath = glob.glob(globpath)
986 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
987 % globpath)
988 srcpath = srcpath[0]
989 ld_path = os.path.join(srcpath, 'ld')
990 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
991 ld_path = os.path.join(srcpath, 'ld.bfd')
992 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
993 ld_path = os.path.join(srcpath, 'ld.gold')
994 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
995 % ld_path)
996
997 # Nope, no gold support to be found.
998 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -0700999 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001000 else:
1001 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001002 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001003
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001004 # Package the binutils-bin directory without the '-gold' suffix
1005 # if gold is not enabled as the default linker for this target.
1006 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1007 if not gold_supported:
1008 srcpath = srcpath[:-len('-gold')]
1009 ld_path = os.path.join(srcpath, 'ld')
1010 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1011
Mike Frysinger78b7a812014-11-26 19:45:23 -05001012 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001013 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1014 for prog in os.listdir(output_dir + srcpath):
1015 # Skip binaries already wrapped.
1016 if not prog.endswith('.real'):
1017 GeneratePathWrapper(output_dir, binpath + prog,
1018 os.path.join(srcpath, prog))
1019 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1020 os.path.join(srcpath, prog))
1021
David James27ac4ae2012-12-03 23:16:15 -08001022 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001023 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1024 if gold_supported:
1025 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001026 else:
1027 # If gold is not enabled as the default linker and 2 env.d
1028 # files exist, pick the one without the '-gold' suffix.
1029 envds = sorted(glob.glob(envd))
1030 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1031 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001032 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1033 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1034 output_dir + libpath)
1035
1036
1037def _ProcessGccConfig(target, output_dir):
1038 """Do what gcc-config would have done"""
1039 binpath = '/bin'
1040 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1041 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1042 for prog in os.listdir(output_dir + srcpath):
1043 # Skip binaries already wrapped.
1044 if (not prog.endswith('.real') and
1045 not prog.endswith('.elf') and
1046 prog.startswith(target)):
1047 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1048 os.path.join(srcpath, prog))
1049 return srcpath
1050
1051
Frank Henigman179ec7c2015-02-06 03:01:09 -05001052def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1053 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001054 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001055 for sysroot_wrapper in glob.glob(os.path.join(
1056 output_dir + srcpath, 'sysroot_wrapper*')):
1057 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1058 for num in xrange(len(contents)):
1059 if '@CCACHE_DEFAULT@' in contents[num]:
1060 contents[num] = 'use_ccache = False'
1061 break
1062 # Can't update the wrapper in place since it's a hardlink to a file in /.
1063 os.unlink(sysroot_wrapper)
1064 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1065 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001066
1067
1068def _ProcessDistroCleanups(target, output_dir):
1069 """Clean up the tree and remove all distro-specific requirements
1070
1071 Args:
1072 target: The toolchain target name
1073 output_dir: The output directory to clean up
1074 """
1075 _ProcessBinutilsConfig(target, output_dir)
1076 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001077 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001078
1079 osutils.RmDir(os.path.join(output_dir, 'etc'))
1080
1081
1082def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1083 """Setup a tree from the packages for the specified target
1084
1085 This populates a path with all the files from toolchain packages so that
1086 a tarball can easily be generated from the result.
1087
1088 Args:
1089 target: The target to create a packagable root from
1090 output_dir: The output directory to place all the files
1091 ldpaths: A dict of static ldpath information
1092 root: The root path to pull all packages/files from
1093 """
1094 # Find all the files owned by the packages for this target.
1095 paths, elfs = _GetFilesForTarget(target, root=root)
1096
1097 # Link in all the package's files, any ELF dependencies, and wrap any
1098 # executable ELFs with helper scripts.
1099 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001100 """Move /usr/bin to /bin so people can just use that toplevel dir
1101
1102 Note we do not apply this to clang - there is correlation between clang's
1103 search path for libraries / inclusion and its installation path.
1104 """
1105 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1106 return path[4:]
1107 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001108 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1109 path_rewrite_func=MoveUsrBinToBin, root=root)
1110
1111 # The packages, when part of the normal distro, have helper scripts
1112 # that setup paths and such. Since we are making this standalone, we
1113 # need to preprocess all that ourselves.
1114 _ProcessDistroCleanups(target, output_dir)
1115
1116
1117def CreatePackages(targets_wanted, output_dir, root='/'):
1118 """Create redistributable cross-compiler packages for the specified targets
1119
1120 This creates toolchain packages that should be usable in conjunction with
1121 a downloaded sysroot (created elsewhere).
1122
1123 Tarballs (one per target) will be created in $PWD.
1124
1125 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001126 targets_wanted: The targets to package up.
1127 output_dir: The directory to put the packages in.
1128 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001129 """
Ralph Nathan03047282015-03-23 11:09:32 -07001130 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001131 osutils.SafeMakedirs(output_dir)
1132 ldpaths = lddtree.LoadLdpaths(root)
1133 targets = ExpandTargets(targets_wanted)
1134
David James4bc13702013-03-26 08:08:04 -07001135 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001136 # We have to split the root generation from the compression stages. This is
1137 # because we hardlink in all the files (to avoid overhead of reading/writing
1138 # the copies multiple times). But tar gets angry if a file's hardlink count
1139 # changes from when it starts reading a file to when it finishes.
1140 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1141 for target in targets:
1142 output_target_dir = os.path.join(tempdir, target)
1143 queue.put([target, output_target_dir, ldpaths, root])
1144
1145 # Build the tarball.
1146 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1147 for target in targets:
1148 tar_file = os.path.join(output_dir, target + '.tar.xz')
1149 queue.put([tar_file, os.path.join(tempdir, target)])
1150
1151
Brian Harring30675052012-02-29 12:18:22 -08001152def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -05001153 parser = commandline.ArgumentParser(description=__doc__)
1154 parser.add_argument('-u', '--nousepkg',
1155 action='store_false', dest='usepkg', default=True,
1156 help='Use prebuilt packages if possible')
1157 parser.add_argument('-d', '--deleteold',
1158 action='store_true', dest='deleteold', default=False,
1159 help='Unmerge deprecated packages')
1160 parser.add_argument('-t', '--targets',
1161 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001162 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001163 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001164 "allowed. Defaults to 'sdk'.")
1165 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1166 help='Comma separated list of boards whose toolchains we '
1167 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001168 parser.add_argument('--hostonly',
1169 dest='hostonly', default=False, action='store_true',
1170 help='Only setup the host toolchain. '
1171 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001172 parser.add_argument('--show-board-cfg', '--show-cfg',
1173 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001174 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001175 parser.add_argument('--create-packages',
1176 action='store_true', default=False,
1177 help='Build redistributable packages')
1178 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1179 help='Output directory')
1180 parser.add_argument('--reconfig', default=False, action='store_true',
1181 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001182 parser.add_argument('--sysroot', type='path',
1183 help='The sysroot in which to install the toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001184
Mike Frysinger0c808452014-11-06 17:30:23 -05001185 options = parser.parse_args(argv)
1186 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001187
Mike Frysinger35247af2012-11-16 18:58:06 -05001188 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001189 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001190 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001191
Gilad Arnold8195b532015-04-07 10:56:30 +03001192 targets_wanted = set(options.targets.split(','))
1193 boards_wanted = (set(options.include_boards.split(','))
1194 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001195
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001196 if options.cfg_name:
1197 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001198 elif options.create_packages:
1199 cros_build_lib.AssertInsideChroot()
1200 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001201 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001202 else:
1203 cros_build_lib.AssertInsideChroot()
1204 # This has to be always run as root.
1205 if os.geteuid() != 0:
1206 cros_build_lib.Die('this script must be run as root')
1207
1208 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001209 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001210 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001211 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001212 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001213 Crossdev.Save()
1214
1215 return 0