blob: 6ff71e0a24fe61f2a2a41255c7e09a0bd53c6483 [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
Don Garrett88b8d782014-05-13 17:30:55 -070015from chromite.cbuildbot 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',
61 'i686-pc-linux-gnu',
62 'armv7a-cros-linux-gnueabi',
63)
64CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
65
Zdenek Behan508dcce2011-12-05 15:39:32 +010066# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
67CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050068 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040069 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080070 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050071 'i686-pc-linux-gnu' : '-gold',
72 'x86_64-cros-linux-gnu' : '-gold',
73 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010074}
Zdenek Behan508dcce2011-12-05 15:39:32 +010075# Global per-run cache that will be filled ondemand in by GetPackageMap()
76# function as needed.
77target_version_map = {
78}
79
80
David James66a09c42012-11-05 13:31:38 -080081class Crossdev(object):
82 """Class for interacting with crossdev and caching its output."""
83
84 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
85 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -080086 # Packages that needs separate handling, in addition to what we have from
87 # crossdev.
88 MANUAL_PKGS = {
89 'llvm': 'sys-devel',
90 }
David James66a09c42012-11-05 13:31:38 -080091
92 @classmethod
93 def Load(cls, reconfig):
94 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080095 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
96 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080097 if os.path.exists(cls._CACHE_FILE) and not reconfig:
98 with open(cls._CACHE_FILE) as f:
99 data = json.load(f)
David James90239b92012-11-05 15:31:34 -0800100 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -0800101 cls._CACHE = data
102
103 @classmethod
104 def Save(cls):
105 """Store crossdev cache on disk."""
106 # Save the cache from the successful run.
107 with open(cls._CACHE_FILE, 'w') as f:
108 json.dump(cls._CACHE, f)
109
110 @classmethod
111 def GetConfig(cls, target):
112 """Returns a map of crossdev provided variables about a tuple."""
113 CACHE_ATTR = '_target_tuple_map'
114
115 val = cls._CACHE.setdefault(CACHE_ATTR, {})
116 if not target in val:
117 # Find out the crossdev tuple.
118 target_tuple = target
119 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800120 target_tuple = toolchain.GetHostTuple()
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700121 # Build the crossdev command.
122 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
123 if target in TARGET_GO_ENABLED:
124 cmd.extend(CROSSDEV_GO_ARGS)
125 cmd.extend(['-t', target_tuple])
David James66a09c42012-11-05 13:31:38 -0800126 # Catch output of crossdev.
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700127 out = cros_build_lib.RunCommand(cmd, print_cmd=False,
128 redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800129 # List of tuples split at the first '=', converted into dict.
Han Shene23782f2016-02-18 12:20:00 -0800130 conf = dict((k, cros_build_lib.ShellUnquote(v))
131 for k, v in (x.split('=', 1) for x in out))
132 conf['crosspkgs'] = conf['crosspkgs'].split()
133
134 for pkg, cat in cls.MANUAL_PKGS.iteritems():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400135 conf[pkg + '_pn'] = pkg
136 conf[pkg + '_category'] = cat
137 if pkg not in conf['crosspkgs']:
138 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800139
140 val[target] = conf
141
David James66a09c42012-11-05 13:31:38 -0800142 return val[target]
143
144 @classmethod
145 def UpdateTargets(cls, targets, usepkg, config_only=False):
146 """Calls crossdev to initialize a cross target.
147
148 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700149 targets: The list of targets to initialize using crossdev.
150 usepkg: Copies the commandline opts.
151 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800152 """
153 configured_targets = cls._CACHE.setdefault('configured_targets', [])
154
155 cmdbase = ['crossdev', '--show-fail-log']
156 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
157 # Pick stable by default, and override as necessary.
158 cmdbase.extend(['-P', '--oneshot'])
159 if usepkg:
160 cmdbase.extend(['-P', '--getbinpkg',
161 '-P', '--usepkgonly',
162 '--without-headers'])
163
Christopher Wileyb22c0712015-06-02 10:37:03 -0700164 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800165 cmdbase.extend(['--overlays', overlays])
166 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
167
168 for target in targets:
169 if config_only and target in configured_targets:
170 continue
171
172 cmd = cmdbase + ['-t', target]
173
174 for pkg in GetTargetPackages(target):
175 if pkg == 'gdb':
176 # Gdb does not have selectable versions.
177 cmd.append('--ex-gdb')
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700178 elif pkg == 'ex_go':
179 # Go does not have selectable versions.
180 cmd.extend(CROSSDEV_GO_ARGS)
Han Shene23782f2016-02-18 12:20:00 -0800181 elif pkg in cls.MANUAL_PKGS:
182 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700183 else:
184 # The first of the desired versions is the "primary" one.
185 version = GetDesiredPackageVersions(target, pkg)[0]
186 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800187
188 cmd.extend(targets[target]['crossdev'].split())
189 if config_only:
190 # In this case we want to just quietly reinit
191 cmd.append('--init-target')
192 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
193 else:
194 cros_build_lib.RunCommand(cmd)
195
196 configured_targets.append(target)
197
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100198
Zdenek Behan508dcce2011-12-05 15:39:32 +0100199def GetPackageMap(target):
200 """Compiles a package map for the given target from the constants.
201
202 Uses a cache in target_version_map, that is dynamically filled in as needed,
203 since here everything is static data and the structuring is for ease of
204 configurability only.
205
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500206 Args:
207 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100208
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500209 Returns:
210 A map between packages and desired versions in internal format
211 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100212 """
213 if target in target_version_map:
214 return target_version_map[target]
215
216 # Start from copy of the global defaults.
217 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
218
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100219 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100220 # prefer any specific overrides
221 if pkg in TARGET_VERSION_MAP.get(target, {}):
222 result[pkg] = TARGET_VERSION_MAP[target][pkg]
223 else:
224 # finally, if not already set, set a sane default
225 result.setdefault(pkg, DEFAULT_VERSION)
226 target_version_map[target] = result
227 return result
228
229
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100230def GetTargetPackages(target):
231 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800232 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100233 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800234 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100235
236
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100237# Portage helper functions:
238def GetPortagePackage(target, package):
239 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800240 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100241 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800242 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100243 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100244 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100245 category = conf['category']
246 # Portage package:
247 pn = conf[package + '_pn']
248 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500249 assert category
250 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100251 return '%s/%s' % (category, pn)
252
253
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100254def IsPackageDisabled(target, package):
255 """Returns if the given package is not used for the target."""
256 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
257
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100258
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700259def PortageTrees(root):
260 """Return the portage trees for a given root."""
261 if root == '/':
262 return portage.db['/']
263 # The portage logic requires the path always end in a slash.
264 root = root.rstrip('/') + '/'
265 return portage.create_trees(target_root=root, config_root=root)[root]
266
267
268def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100269 """Extracts the list of current versions of a target, package pair.
270
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500271 Args:
272 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700273 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100274
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500275 Returns:
276 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100277 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100278 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500279 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700280 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100281 version = portage.versions.cpv_getversion(pkg)
282 versions.append(version)
283 return versions
284
285
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700286def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100287 """Extracts the current stable version for a given package.
288
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500289 Args:
290 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
291 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700292 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100293
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500294 Returns:
295 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100296 """
David James90239b92012-11-05 15:31:34 -0800297 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500298 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700299 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800300 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100301
302
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700303def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100304 """Resolves keywords in a given version list for a particular package.
305
306 Resolving means replacing PACKAGE_STABLE with the actual number.
307
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500308 Args:
309 target: The target to operate on (e.g. i686-pc-linux-gnu)
310 package: The target/package to operate on (e.g. gcc)
311 versions: List of versions to resolve
312 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700313 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100314
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500315 Returns:
316 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100317 """
318 resolved = []
David James90239b92012-11-05 15:31:34 -0800319 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700320 if not installed:
321 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100322 for version in versions:
323 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700324 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100325 elif version != PACKAGE_NONE:
326 resolved.append(version)
327 return resolved
328
329
330def GetDesiredPackageVersions(target, package):
331 """Produces the list of desired versions for each target, package pair.
332
333 The first version in the list is implicitly treated as primary, ie.
334 the version that will be initialized by crossdev and selected.
335
336 If the version is PACKAGE_STABLE, it really means the current version which
337 is emerged by using the package atom with no particular version key.
338 Since crossdev unmasks all packages by default, this will actually
339 mean 'unstable' in most cases.
340
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500341 Args:
342 target: The target to operate on (e.g. i686-pc-linux-gnu)
343 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100344
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500345 Returns:
346 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100347 """
348 packagemap = GetPackageMap(target)
349
350 versions = []
351 if package in packagemap:
352 versions.append(packagemap[package])
353
354 return versions
355
356
357def TargetIsInitialized(target):
358 """Verifies if the given list of targets has been correctly initialized.
359
360 This determines whether we have to call crossdev while emerging
361 toolchain packages or can do it using emerge. Emerge is naturally
362 preferred, because all packages can be updated in a single pass.
363
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500364 Args:
365 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100366
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500367 Returns:
368 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100369 """
370 # Check if packages for the given target all have a proper version.
371 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100372 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800373 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100374 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800375 if not IsPackageDisabled(target, package) and not (
376 GetStablePackageVersion(atom, True) and
377 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100378 return False
379 return True
380 except cros_build_lib.RunCommandError:
381 # Fails - The target has likely never been initialized before.
382 return False
383
384
385def RemovePackageMask(target):
386 """Removes a package.mask file for the given platform.
387
388 The pre-existing package.mask files can mess with the keywords.
389
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500390 Args:
391 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392 """
393 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700394 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100395
396
Zdenek Behan508dcce2011-12-05 15:39:32 +0100397# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700398def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500399 """Rebuild libtool as needed
400
401 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
402 gcc, libtool will break. We can't use binary packages either as those will
403 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700404
405 Args:
406 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500407 """
408 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700409 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500410 for line in f:
411 # Look for a line like:
412 # sys_lib_search_path_spec="..."
413 # It'll be a list of paths and gcc will be one of them.
414 if line.startswith('sys_lib_search_path_spec='):
415 line = line.rstrip()
416 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400417 root_path = os.path.join(root, path.lstrip(os.path.sep))
418 logging.debug('Libtool: checking %s', root_path)
419 if not os.path.exists(root_path):
420 logging.info('Rebuilding libtool after gcc upgrade')
421 logging.info(' %s', line)
422 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500423 needs_update = True
424 break
425
426 if needs_update:
427 break
428
429 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700430 cmd = [EMERGE_CMD, '--oneshot']
431 if root != '/':
432 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
433 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500434 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400435 else:
436 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500437
438
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700439def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100440 """Determines which packages need update/unmerge and defers to portage.
441
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500442 Args:
443 targets: The list of targets to update
444 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700445 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100446 """
David James90239b92012-11-05 15:31:34 -0800447 # Remove keyword files created by old versions of cros_setup_toolchains.
448 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100449
450 # For each target, we do two things. Figure out the list of updates,
451 # and figure out the appropriate keywords/masks. Crossdev will initialize
452 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400453 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800454 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100455 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400456 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100457 # Record the highest needed version for each target, for masking purposes.
458 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100459 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100460 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100461 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400462 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100463 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400464 logging.debug(' Updating package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100465 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700466 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100467 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200468 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100469 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100470
Zdenek Behan508dcce2011-12-05 15:39:32 +0100471 packages = []
472 for pkg in mergemap:
473 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200474 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800475 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100476
477 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400478 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800479 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100480
Mike Frysinger3bba5032016-09-20 14:15:04 -0400481 logging.info('Updating packages:')
482 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100483
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100484 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100485 if usepkg:
486 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700487 if root != '/':
488 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100489
490 cmd.extend(packages)
491 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800492 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100493
494
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700495def CleanTargets(targets, root='/'):
496 """Unmerges old packages that are assumed unnecessary.
497
498 Args:
499 targets: The list of targets to clean up.
500 root: The install root in which we want packages cleaned up.
501 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100502 unmergemap = {}
503 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400504 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100505 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100506 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400507 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100508 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400509 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100510 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700511 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100512 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700513 # NOTE: This refers to installed packages (vartree) rather than the
514 # Portage version (porttree and/or bintree) when determining the current
515 # version. While this isn't the most accurate thing to do, it is probably
516 # a good simple compromise, which should have the desired result of
517 # uninstalling everything but the latest installed version. In
518 # particular, using the bintree (--usebinpkg) requires a non-trivial
519 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200520 desired_num = VersionListToNumeric(target, package, desired, True)
521 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400522 logging.warning('Error detecting stable version for %s, '
523 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200524 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100525 unmergemap[pkg] = set(current).difference(desired_num)
526
527 # Cleaning doesn't care about consistency and rebuilding package.* files.
528 packages = []
529 for pkg, vers in unmergemap.iteritems():
530 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
531
532 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400533 logging.info('Cleaning packages:')
534 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100535 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700536 if root != '/':
537 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100538 cmd.extend(packages)
539 cros_build_lib.RunCommand(cmd)
540 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400541 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542
543
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700544def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100545 """Runs gcc-config and binutils-config to select the desired.
546
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500547 Args:
548 targets: The targets to select
549 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700550 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100551 """
552 for package in ['gcc', 'binutils']:
553 for target in targets:
554 # Pick the first version in the numbered list as the selected one.
555 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700556 desired_num = VersionListToNumeric(target, package, desired, True,
557 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100558 desired = desired_num[0]
559 # *-config does not play revisions, strip them, keep just PV.
560 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
561
562 if target == 'host':
563 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800564 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100565
566 # And finally, attach target to it.
567 desired = '%s-%s' % (target, desired)
568
569 # Target specific hacks
570 if package in suffixes:
571 if target in suffixes[package]:
572 desired += suffixes[package][target]
573
David James7ec5efc2012-11-06 09:39:49 -0800574 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700575 if root != '/':
576 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800577 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500578 result = cros_build_lib.RunCommand(
579 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
580 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700581
582 # Do not reconfig when the current is live or nothing needs to be done.
583 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100584 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500585 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700586 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100587
588
Mike Frysinger35247af2012-11-16 18:58:06 -0500589def ExpandTargets(targets_wanted):
590 """Expand any possible toolchain aliases into full targets
591
592 This will expand 'all' and 'sdk' into the respective toolchain tuples.
593
594 Args:
595 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500596
Mike Frysinger35247af2012-11-16 18:58:06 -0500597 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300598 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500599 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500600 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700601 if targets_wanted == set(['boards']):
602 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300603 return {}
604
605 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500606 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300607 return all_targets
608 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500609 # Filter out all the non-sdk toolchains as we don't want to mess
610 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300611 return toolchain.FilterToolchains(all_targets, 'sdk', True)
612
613 # Verify user input.
614 nonexistent = targets_wanted.difference(all_targets)
615 if nonexistent:
616 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
617 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500618
619
David Jamesf8c672f2012-11-06 13:38:11 -0800620def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700621 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100622 """Performs all steps to create a synchronized toolchain enviroment.
623
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500624 Args:
625 usepkg: Use prebuilt packages
626 deleteold: Unmerge deprecated packages
627 hostonly: Only setup the host toolchain
628 reconfig: Reload crossdev config and reselect toolchains
629 targets_wanted: All the targets to update
630 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700631 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100632 """
David Jamesf8c672f2012-11-06 13:38:11 -0800633 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100634 if not hostonly:
635 # For hostonly, we can skip most of the below logic, much of which won't
636 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500637 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400638
Don Garrettc0c74002015-10-09 12:58:19 -0700639 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300640 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400641 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800642 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100643
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100644 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400645 for target in targets:
646 if TargetIsInitialized(target):
647 reconfig_targets[target] = targets[target]
648 else:
649 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100650 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400651 logging.info('The following targets need to be re-initialized:')
652 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800653 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200654 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800655 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100656
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100657 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400658 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100659
660 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700661 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
662 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800663
664 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700665 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100666
Mike Frysingerc880a962013-11-08 13:59:06 -0500667 # Now that we've cleared out old versions, see if we need to rebuild
668 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700669 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500670
Zdenek Behan508dcce2011-12-05 15:39:32 +0100671
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700672def ShowConfig(name):
673 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500674
675 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700676 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500677 """
Don Garrettc0c74002015-10-09 12:58:19 -0700678 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500679 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400680 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400681 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800682 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400683 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500684
685
Mike Frysinger35247af2012-11-16 18:58:06 -0500686def GeneratePathWrapper(root, wrappath, path):
687 """Generate a shell script to execute another shell script
688
689 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
690 argv[0] won't be pointing to the correct path, generate a shell script that
691 just executes another program with its full path.
692
693 Args:
694 root: The root tree to generate scripts inside of
695 wrappath: The full path (inside |root|) to create the wrapper
696 path: The target program which this wrapper will execute
697 """
698 replacements = {
699 'path': path,
700 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
701 }
702 wrapper = """#!/bin/sh
703base=$(realpath "$0")
704basedir=${base%%/*}
705exec "${basedir}/%(relroot)s%(path)s" "$@"
706""" % replacements
707 root_wrapper = root + wrappath
708 if os.path.islink(root_wrapper):
709 os.unlink(root_wrapper)
710 else:
711 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
712 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400713 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500714
715
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700716def FixClangXXWrapper(root, path):
717 """Fix wrapper shell scripts and symlinks for invoking clang++
718
719 In a typical installation, clang++ symlinks to clang, which symlinks to the
720 elf executable. The executable distinguishes between clang and clang++ based
721 on argv[0].
722
723 When invoked through the LdsoWrapper, argv[0] always contains the path to the
724 executable elf file, making clang/clang++ invocations indistinguishable.
725
726 This function detects if the elf executable being wrapped is clang-X.Y, and
727 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
728
729 The calling sequence now becomes:
730 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
731 the Ldsowrapper).
732 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
733 to the original clang-3.9 elf.
734 -) The difference this time is that inside the elf file execution, $0 is
735 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
736
737 Args:
738 root: The root tree to generate scripts / symlinks inside of
739 path: The target elf for which LdsoWrapper was created
740 """
741 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
742 logging.info('fixing clang++ invocation for %s', path)
743 clangdir = os.path.dirname(root + path)
744 clang = os.path.basename(path)
745 clangxx = clang.replace('clang', 'clang++')
746
747 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
748 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
749
750 # Create a hardlink clang++-X.Y pointing to clang-X.Y
751 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
752
753 # Adjust the clang++ symlink to point to clang++-X.Y
754 os.unlink(os.path.join(clangdir, 'clang++'))
755 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
756
757
Mike Frysinger35247af2012-11-16 18:58:06 -0500758def FileIsCrosSdkElf(elf):
759 """Determine if |elf| is an ELF that we execute in the cros_sdk
760
761 We don't need this to be perfect, just quick. It makes sure the ELF
762 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
763
764 Args:
765 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500766
Mike Frysinger35247af2012-11-16 18:58:06 -0500767 Returns:
768 True if we think |elf| is a native ELF
769 """
770 with open(elf) as f:
771 data = f.read(20)
772 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
773 return (data[0:4] == '\x7fELF' and
774 data[4] == '\x02' and
775 data[5] == '\x01' and
776 data[18] == '\x3e')
777
778
779def IsPathPackagable(ptype, path):
780 """Should the specified file be included in a toolchain package?
781
782 We only need to handle files as we'll create dirs as we need them.
783
784 Further, trim files that won't be useful:
785 - non-english translations (.mo) since it'd require env vars
786 - debug files since these are for the host compiler itself
787 - info/man pages as they're big, and docs are online, and the
788 native docs should work fine for the most part (`man gcc`)
789
790 Args:
791 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
792 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500793
Mike Frysinger35247af2012-11-16 18:58:06 -0500794 Returns:
795 True if we want to include this path in the package
796 """
797 return not (ptype in ('dir',) or
798 path.startswith('/usr/lib/debug/') or
799 os.path.splitext(path)[1] == '.mo' or
800 ('/man/' in path or '/info/' in path))
801
802
803def ReadlinkRoot(path, root):
804 """Like os.readlink(), but relative to a |root|
805
806 Args:
807 path: The symlink to read
808 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500809
Mike Frysinger35247af2012-11-16 18:58:06 -0500810 Returns:
811 A fully resolved symlink path
812 """
813 while os.path.islink(root + path):
814 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
815 return path
816
817
818def _GetFilesForTarget(target, root='/'):
819 """Locate all the files to package for |target|
820
821 This does not cover ELF dependencies.
822
823 Args:
824 target: The toolchain target name
825 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500826
Mike Frysinger35247af2012-11-16 18:58:06 -0500827 Returns:
828 A tuple of a set of all packable paths, and a set of all paths which
829 are also native ELFs
830 """
831 paths = set()
832 elfs = set()
833
834 # Find all the files owned by the packages for this target.
835 for pkg in GetTargetPackages(target):
836 # Ignore packages that are part of the target sysroot.
837 if pkg in ('kernel', 'libc'):
838 continue
839
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700840 # Skip Go compiler from redistributable packages.
841 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
842 # into it. Due to this, the toolchain cannot be unpacked anywhere
843 # else and be readily useful. To enable packaging Go, we need to:
844 # -) Tweak the wrappers/environment to override GOROOT
845 # automatically based on the unpack location.
846 # -) Make sure the ELF dependency checking and wrapping logic
847 # below skips the Go toolchain executables and libraries.
848 # -) Make sure the packaging process maintains the relative
849 # timestamps of precompiled standard library packages.
850 # (see dev-lang/go ebuild for details).
851 if pkg == 'ex_go':
852 continue
853
Mike Frysinger35247af2012-11-16 18:58:06 -0500854 atom = GetPortagePackage(target, pkg)
855 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700856 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700857 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500858
859 # pylint: disable=E1101
860 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
861 settings=portage.settings)
862 contents = dblink.getcontents()
863 for obj in contents:
864 ptype = contents[obj][0]
865 if not IsPathPackagable(ptype, obj):
866 continue
867
868 if ptype == 'obj':
869 # For native ELFs, we need to pull in their dependencies too.
870 if FileIsCrosSdkElf(obj):
871 elfs.add(obj)
872 paths.add(obj)
873
874 return paths, elfs
875
876
877def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500878 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500879 """Link in all packable files and their runtime dependencies
880
881 This also wraps up executable ELFs with helper scripts.
882
883 Args:
884 output_dir: The output directory to store files
885 paths: All the files to include
886 elfs: All the files which are ELFs (a subset of |paths|)
887 ldpaths: A dict of static ldpath information
888 path_rewrite_func: User callback to rewrite paths in output_dir
889 root: The root path to pull all packages/files from
890 """
891 # Link in all the files.
892 sym_paths = []
893 for path in paths:
894 new_path = path_rewrite_func(path)
895 dst = output_dir + new_path
896 osutils.SafeMakedirs(os.path.dirname(dst))
897
898 # Is this a symlink which we have to rewrite or wrap?
899 # Delay wrap check until after we have created all paths.
900 src = root + path
901 if os.path.islink(src):
902 tgt = os.readlink(src)
903 if os.path.sep in tgt:
904 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
905
906 # Rewrite absolute links to relative and then generate the symlink
907 # ourselves. All other symlinks can be hardlinked below.
908 if tgt[0] == '/':
909 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
910 os.symlink(tgt, dst)
911 continue
912
913 os.link(src, dst)
914
915 # Now see if any of the symlinks need to be wrapped.
916 for sym, tgt in sym_paths:
917 if tgt in elfs:
918 GeneratePathWrapper(output_dir, sym, tgt)
919
920 # Locate all the dependencies for all the ELFs. Stick them all in the
921 # top level "lib" dir to make the wrapper simpler. This exact path does
922 # not matter since we execute ldso directly, and we tell the ldso the
923 # exact path to search for its libraries.
924 libdir = os.path.join(output_dir, 'lib')
925 osutils.SafeMakedirs(libdir)
926 donelibs = set()
927 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400928 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500929 interp = e['interp']
930 if interp:
931 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400932 interp = os.path.join('/lib', os.path.basename(interp))
933 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
934 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700935 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500936
937 for lib, lib_data in e['libs'].iteritems():
938 if lib in donelibs:
939 continue
940
941 src = path = lib_data['path']
942 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700943 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500944 continue
945 donelibs.add(lib)
946
947 # Needed libs are the SONAME, but that is usually a symlink, not a
948 # real file. So link in the target rather than the symlink itself.
949 # We have to walk all the possible symlinks (SONAME could point to a
950 # symlink which points to a symlink), and we have to handle absolute
951 # ourselves (since we have a "root" argument).
952 dst = os.path.join(libdir, os.path.basename(path))
953 src = ReadlinkRoot(src, root)
954
955 os.link(root + src, dst)
956
957
958def _EnvdGetVar(envd, var):
959 """Given a Gentoo env.d file, extract a var from it
960
961 Args:
962 envd: The env.d file to load (may be a glob path)
963 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500964
Mike Frysinger35247af2012-11-16 18:58:06 -0500965 Returns:
966 The value of |var|
967 """
968 envds = glob.glob(envd)
969 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
970 envd = envds[0]
971 return cros_build_lib.LoadKeyValueFile(envd)[var]
972
973
974def _ProcessBinutilsConfig(target, output_dir):
975 """Do what binutils-config would have done"""
976 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500977
978 # Locate the bin dir holding the gold linker.
979 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
980 target, 'binutils-bin')
981 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500982 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500983 if not srcpath:
984 # Maybe this target doesn't support gold.
985 globpath = os.path.join(binutils_bin_path, '*')
986 srcpath = glob.glob(globpath)
987 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
988 % globpath)
989 srcpath = srcpath[0]
990 ld_path = os.path.join(srcpath, 'ld')
991 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
992 ld_path = os.path.join(srcpath, 'ld.bfd')
993 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
994 ld_path = os.path.join(srcpath, 'ld.gold')
995 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
996 % ld_path)
997
998 # Nope, no gold support to be found.
999 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001000 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001001 else:
1002 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
1003 gold_supported = True
Mike Frysinger78b7a812014-11-26 19:45:23 -05001004 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001005
Mike Frysinger78b7a812014-11-26 19:45:23 -05001006 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001007 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1008 for prog in os.listdir(output_dir + srcpath):
1009 # Skip binaries already wrapped.
1010 if not prog.endswith('.real'):
1011 GeneratePathWrapper(output_dir, binpath + prog,
1012 os.path.join(srcpath, prog))
1013 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1014 os.path.join(srcpath, prog))
1015
David James27ac4ae2012-12-03 23:16:15 -08001016 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001017 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1018 if gold_supported:
1019 envd += '-gold'
Mike Frysinger35247af2012-11-16 18:58:06 -05001020 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1021 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1022 output_dir + libpath)
1023
1024
1025def _ProcessGccConfig(target, output_dir):
1026 """Do what gcc-config would have done"""
1027 binpath = '/bin'
1028 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1029 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1030 for prog in os.listdir(output_dir + srcpath):
1031 # Skip binaries already wrapped.
1032 if (not prog.endswith('.real') and
1033 not prog.endswith('.elf') and
1034 prog.startswith(target)):
1035 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1036 os.path.join(srcpath, prog))
1037 return srcpath
1038
1039
Frank Henigman179ec7c2015-02-06 03:01:09 -05001040def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1041 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001042 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001043 for sysroot_wrapper in glob.glob(os.path.join(
1044 output_dir + srcpath, 'sysroot_wrapper*')):
1045 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1046 for num in xrange(len(contents)):
1047 if '@CCACHE_DEFAULT@' in contents[num]:
1048 contents[num] = 'use_ccache = False'
1049 break
1050 # Can't update the wrapper in place since it's a hardlink to a file in /.
1051 os.unlink(sysroot_wrapper)
1052 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1053 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001054
1055
1056def _ProcessDistroCleanups(target, output_dir):
1057 """Clean up the tree and remove all distro-specific requirements
1058
1059 Args:
1060 target: The toolchain target name
1061 output_dir: The output directory to clean up
1062 """
1063 _ProcessBinutilsConfig(target, output_dir)
1064 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001065 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001066
1067 osutils.RmDir(os.path.join(output_dir, 'etc'))
1068
1069
1070def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1071 """Setup a tree from the packages for the specified target
1072
1073 This populates a path with all the files from toolchain packages so that
1074 a tarball can easily be generated from the result.
1075
1076 Args:
1077 target: The target to create a packagable root from
1078 output_dir: The output directory to place all the files
1079 ldpaths: A dict of static ldpath information
1080 root: The root path to pull all packages/files from
1081 """
1082 # Find all the files owned by the packages for this target.
1083 paths, elfs = _GetFilesForTarget(target, root=root)
1084
1085 # Link in all the package's files, any ELF dependencies, and wrap any
1086 # executable ELFs with helper scripts.
1087 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001088 """Move /usr/bin to /bin so people can just use that toplevel dir
1089
1090 Note we do not apply this to clang - there is correlation between clang's
1091 search path for libraries / inclusion and its installation path.
1092 """
1093 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1094 return path[4:]
1095 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001096 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1097 path_rewrite_func=MoveUsrBinToBin, root=root)
1098
1099 # The packages, when part of the normal distro, have helper scripts
1100 # that setup paths and such. Since we are making this standalone, we
1101 # need to preprocess all that ourselves.
1102 _ProcessDistroCleanups(target, output_dir)
1103
1104
1105def CreatePackages(targets_wanted, output_dir, root='/'):
1106 """Create redistributable cross-compiler packages for the specified targets
1107
1108 This creates toolchain packages that should be usable in conjunction with
1109 a downloaded sysroot (created elsewhere).
1110
1111 Tarballs (one per target) will be created in $PWD.
1112
1113 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001114 targets_wanted: The targets to package up.
1115 output_dir: The directory to put the packages in.
1116 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001117 """
Ralph Nathan03047282015-03-23 11:09:32 -07001118 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001119 osutils.SafeMakedirs(output_dir)
1120 ldpaths = lddtree.LoadLdpaths(root)
1121 targets = ExpandTargets(targets_wanted)
1122
David James4bc13702013-03-26 08:08:04 -07001123 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001124 # We have to split the root generation from the compression stages. This is
1125 # because we hardlink in all the files (to avoid overhead of reading/writing
1126 # the copies multiple times). But tar gets angry if a file's hardlink count
1127 # changes from when it starts reading a file to when it finishes.
1128 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1129 for target in targets:
1130 output_target_dir = os.path.join(tempdir, target)
1131 queue.put([target, output_target_dir, ldpaths, root])
1132
1133 # Build the tarball.
1134 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1135 for target in targets:
1136 tar_file = os.path.join(output_dir, target + '.tar.xz')
1137 queue.put([tar_file, os.path.join(tempdir, target)])
1138
1139
Brian Harring30675052012-02-29 12:18:22 -08001140def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -05001141 parser = commandline.ArgumentParser(description=__doc__)
1142 parser.add_argument('-u', '--nousepkg',
1143 action='store_false', dest='usepkg', default=True,
1144 help='Use prebuilt packages if possible')
1145 parser.add_argument('-d', '--deleteold',
1146 action='store_true', dest='deleteold', default=False,
1147 help='Unmerge deprecated packages')
1148 parser.add_argument('-t', '--targets',
1149 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001150 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001151 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001152 "allowed. Defaults to 'sdk'.")
1153 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1154 help='Comma separated list of boards whose toolchains we '
1155 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001156 parser.add_argument('--hostonly',
1157 dest='hostonly', default=False, action='store_true',
1158 help='Only setup the host toolchain. '
1159 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001160 parser.add_argument('--show-board-cfg', '--show-cfg',
1161 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001162 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001163 parser.add_argument('--create-packages',
1164 action='store_true', default=False,
1165 help='Build redistributable packages')
1166 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1167 help='Output directory')
1168 parser.add_argument('--reconfig', default=False, action='store_true',
1169 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001170 parser.add_argument('--sysroot', type='path',
1171 help='The sysroot in which to install the toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001172
Mike Frysinger0c808452014-11-06 17:30:23 -05001173 options = parser.parse_args(argv)
1174 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001175
Mike Frysinger35247af2012-11-16 18:58:06 -05001176 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001177 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001178 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001179
Gilad Arnold8195b532015-04-07 10:56:30 +03001180 targets_wanted = set(options.targets.split(','))
1181 boards_wanted = (set(options.include_boards.split(','))
1182 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001183
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001184 if options.cfg_name:
1185 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001186 elif options.create_packages:
1187 cros_build_lib.AssertInsideChroot()
1188 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001189 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001190 else:
1191 cros_build_lib.AssertInsideChroot()
1192 # This has to be always run as root.
1193 if os.geteuid() != 0:
1194 cros_build_lib.Die('this script must be run as root')
1195
1196 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001197 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001198 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001199 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001200 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001201 Crossdev.Save()
1202
1203 return 0